Cod sursa(job #998356)

Utilizator alex_unixPetenchea Alexandru alex_unix Data 16 septembrie 2013 20:11:22
Problema Santa Scor 50
Compilator cpp Status done
Runda Arhiva de probleme Marime 5.93 kb

#include <cstdio>
#include <vector>
#include <utility>
#include <stack>
#include <algorithm>
#include <bitset>
#include <queue>
#include <cstring>

typedef std::pair<int,int> Edge;

const int MAX_N(45005);
const int MAX_SIZE(17);

int n, m, s, e, q, Start, End;
std::vector<int> Graph [MAX_N];
std::vector<std::vector<int>> Components;
bool Flag [MAX_N];
int Level [MAX_N];
int Low [MAX_N];
bool Valid(true);
std::deque<int> Result;
std::stack<Edge> Stack;
std::bitset<MAX_N> Cs, Ce, Cq;
std::vector<int> InsideComponent [MAX_N];
std::vector<Edge> Tree [MAX_N];
int Pred [MAX_N];
int PredPoint [MAX_N];
std::vector<int> Path;
std::vector<int> Points;
int Dp [1 << MAX_SIZE] [MAX_SIZE];
int Index [MAX_N];
bool Mark [MAX_N];

inline void Read (void)
{
	std::freopen("santa.in","r",stdin);
	std::scanf("%d %d",&n,&m);
	for (int i(1), a, b ; i <= m ; ++i)
	{
		std::scanf("%d %d",&a,&b);
		Graph[a].push_back(b);
		Graph[b].push_back(a);
	}
	std::scanf("%d %d %d",&s,&e,&q);
	std::fclose(stdin);
}

inline void Print (void)
{
	std::freopen("santa.out","w",stdout);
	if (Valid)
	{
		std::printf("%d\n",static_cast<int>(Result.size()));
		for (auto it : Result)
			std::printf("%d ",it);
	}
	else
		std::printf("No chance");
	std::putchar('\n');
	std::fclose(stdout);
}

void BiconnectedComponent (Edge x)
{
	static std::bitset<MAX_N> Mark;
	static std::vector<int> c;
	Mark.reset();
	c.clear();
	while (Stack.top() != x)
	{
		Mark[Stack.top().first] = Mark[Stack.top().second] = true;
		Stack.pop();
	}
	Mark[x.first] = Mark[x.second] = true;
	Stack.pop();
	for (int i(1) ; i <= n ; ++i)
		if (Mark[i])
		{
			c.push_back(i);
			InsideComponent[i].push_back(Components.size());
		}
	if (Mark[s])
		Cs[Components.size()] = true;
	if (Mark[e])
		Ce[Components.size()] = true;
	if (Mark[q])
		Cq[Components.size()] = true;
	Components.push_back(c);
}

void DepthFirstSearch (int node, int parent, int level)
{
	Level[node] = Low[node] = level;
	for (auto it : Graph[node])
		if (it != parent)
		{
			if (Level[it])
				Low[node] = std::min(Level[it],Low[node]);
			else
			{
				Stack.push(std::make_pair(node,it));
				DepthFirstSearch(it,node,level + 1);
				Low[node] = std::min(Low[node],Low[it]);
				if (Low[it] >= Level[node])
				{
					BiconnectedComponent(std::make_pair(node,it));
					Flag[node] = true;
				}
			}
		}
}

inline void Check (void)
{
	if (s == e && q != s)
	{
		Valid = false;
		return;
	}
	if (!(Cq[Start] || Cq[End]))
	{
		Valid = false;
		return;
	}
	if (!Ce[s] && Cq[End] && Flag[e] && e != q)
	{
		Valid = false;
		return;
	}
	if (!Ce[s] && Cq[Start] && Flag[s] && s != q)
		Valid = false;
}

inline void Build (void)
{
	for (int i(0) ; i < static_cast<int>(Components.size()) ; ++i)
		for (auto node : Components[i])
			if (Flag[node])
				for (auto it : InsideComponent[node])
					if (it != i)
						Tree[i].push_back(std::make_pair(it,node));
}

inline void BreadthFirstSearch (void)
{
	int node;
	std::queue<int> Queue;
	std::bitset<MAX_N> Mark;
	for (auto it : InsideComponent[s])
	{
		Queue.push(it);
		Pred[it] = it;
		Mark[it] = true;
	}
	while (!Queue.empty())
	{
		node = Queue.front();
		Queue.pop();
		if (Ce[node])
		{
			End = node;
			return;
		}
		for (auto it : Tree[node])
			if (!Mark[it.first])
			{
				Mark[it.first] = true;
				Pred[it.first] = node;
				PredPoint[it.first] = it.second;
				if (Ce[it.first])
				{
					End = it.first;
					return;
				}
				Queue.push(it.first);
			}
	}
}

inline void RecoverPath (void)
{
	int node(End);
	while (Pred[node] != node)
	{
		Points.push_back(PredPoint[node]);
		Path.push_back(node);
		node = Pred[node];
	}
	Path.push_back(node);
	Start = node;
	std::reverse(Path.begin(),Path.end());
	std::reverse(Points.begin(),Points.end());
}

inline int Bit (const int X)
{
	return 1 << X;
}

inline bool Hamilton (int index, int start, int end = 0)
{
	const int END(1 << Components[index].size());
	std::memset(Dp,0,sizeof(Dp));
	static std::vector<int> Path;
	Path.clear();
	int conf, i, node;
	for (i = 0 ; i < static_cast<int>(Components[index].size()) ; ++i)
	{
		Index[Components[index][i]] = i;
		Mark[Components[index][i]] = true;
	}
	conf = Bit(Index[start]);
	Dp[conf][Index[start]] = -2;
	for (conf = 1 ; conf < END ; ++conf)
		for (i = 0 ; i < static_cast<int>(Components[index].size()) ; ++i)
			if ((conf & Bit(i)) && Dp[conf][i])
				for (auto it : Graph[Components[index][i]])
					if (Mark[it] && !(Bit(Index[it]) & conf) && !Dp[conf | Bit(Index[it])][Index[it]])
						Dp[conf | Bit(Index[it])][Index[it]] = (i ? i : -1);
	bool ok(false);
	if (!end)
		for (auto it : Components[index])
		{
			if (Dp[END - 1][Index[it]])
			{
				node = Index[it];
				if (node == -1)
					node = 0;
				conf = END - 1;
				ok = true;
			}
		}
	else if (Dp[END - 1][Index[end]])
	{
		node = Index[end];
		if (node == -1)
			node = 0;
		conf = END - 1;
		ok = true;
	}
	if (ok)
		while (Dp[conf][node] != -2)
		{
			Path.push_back(node);
			i = conf;
			conf ^= Bit(node);
			node = Dp[i][node];
			if (node == -1)
				node = 0;
		}
	for (i = 0 ; i < static_cast<int>(Components[index].size()) ; ++i)
		Mark[Components[index][i]] = false;
	std::reverse(Path.begin(),Path.end());
	for (i = 0 ; i < static_cast<int>(Path.size()) ; ++i)
		Result.push_back(Components[index][Path[i]]);
	return ok;
}

inline void Dynamic (void)
{
	if (Start == End)
	{
		Valid = Hamilton(Start,q);
		Result.push_front(q);
		return;
	}
	std::vector<int> v;
	if (Cq[Start])
	{
		int node(q);
		for (int i(0) ; i < static_cast<int>(Points.size()) ; ++i)
		{
			Valid = Hamilton(Path[i],node,Points[i]);
			node = Points[i];
			if (!Valid)
				return;
		}
		Valid = Hamilton(End,Points.back());
	}
	else
	{
		int node(q);
		for (int i(Points.size() - 1) ; i >= 0 ; --i)
		{
			Valid = Hamilton(Path[i + 1],node,Points[i]);
			node = Points[i];
			if (!Valid)
				return;
		}
		Valid = Hamilton(Start,Points.front());
	}
	Result.push_front(q);
}

int main (void)
{
	Read();
	DepthFirstSearch(1,1,1);
	Build();
	BreadthFirstSearch();
	RecoverPath();
	Check();
	if (Valid)
		Dynamic();
	Print();
	return 0;
}