Cod sursa(job #528282)

Utilizator mgntMarius B mgnt Data 2 februarie 2011 15:26:39
Problema Santa Scor 70
Compilator cpp Status done
Runda Arhiva de probleme Marime 8.82 kb
#include <cstdio>
#include <algorithm>
using namespace std;

int const maxn=45*1000,maxm=130*1000,maxc=15;

struct edge{int x,y;};

// edges::init changes the representation of the graph
// given by N, number of vertices, and E, array of edges,
// into N, number of vertices, and A,I, adjacency lists.
namespace edges
{
int N; // number of vertices
int M; // number of edges
edge E[maxm]; // edges
int A[maxm*2]; // A[i], i=I[x]..I[x+1]-1 are (read next line)
int I[maxn+1]; // neighbours of vertex x;

void init_I()
{	int i,a,b;
	for(i=0;N>i;++i){I[i]=0;}
	for(i=0;M>i;++i){++I[E[i].x];++I[E[i].y];}
	a=I[0];I[0]=0;for(i=1;N>=i;++i){b=I[i];I[i]=I[i-1]+a;a=b;}
}

void init_A()
{	int i;
	for(i=0;M>i;++i){A[I[E[i].x]++]=E[i].y;A[I[E[i].y]++]=E[i].x;}
}

void init()
{init_I();init_A();init_I();}


};

// biconnected::process computes the biconnected components
// for the graph represented by edges::N,edges::A, and edges::I
namespace biconnected
{
edge E[maxm]; // stack of edges
int T; // top of stack E
edge C[maxn*maxc]; // C[j], j=I[i]..I[i+1]-1, i=0..K-1 are (read next line)
int I[1+maxn]; // edges of biconnected component i
int K; // number of biconnected components
int A[maxn]; // A[i]==1, i is an articulation point; A[i]==0 otherwise
int R; // root of the DFS
int U; // update : detect if root is articulation point
int P[maxn]; // parent of vertex x in the DFS tree
int D[maxn]; // depth of vertex x in the DFS tree
int L[maxn]; // lowpoint of vertex x in the DFS 

void add_component(int tx,int ty)
{	int s=I[K],x,y;
	do
	{	x=E[T].x;y=E[T].y;
		C[s].x=x;C[s].y=y;
		++s;--T;
	}
	while((x!=tx)||(y!=ty));
	++K;I[K]=s;
}

void add_articulation_point(int x)
{	if(x!=R)
	{A[x]=1;}
	else
	{	if(1==U)
		{A[x]=1;}
		U=min(U+1,2);
	}
}

void DFS(int x)
{	int i=edges::I[x],t=edges::I[x+1],y;
	while(i<t)
	{	y=edges::A[i++];
		if(y!=P[x])
		{	if(-1==P[y])
			{	D[y]=D[x]+1;L[y]=D[y];P[y]=x;
				++T;E[T].x=x;E[T].y=y;
				DFS(y);
				L[x]=min(L[x],L[y]);
				if(L[y]>=D[x])
				{	add_component(x,y);
					add_articulation_point(x);
				}
			}
			else
			{	if(D[y]<D[x])
				{	++T;E[T].x=x;E[T].y=y;
					L[x]=min(L[x],D[y]);
				}
			}
		}
	}
}

void process()
{	int i,N=edges::N;
	K=0;I[K]=0;T=-1;
	for(i=0;N>i;++i){P[i]=-1;}
	for(i=0;N>i;++i){A[i]=0;}
	for(i=0;N>i;++i)
	{	if(-1==P[i])
		{	P[i]=i;D[i]=0;L[i]=D[i];R=i;U=0;DFS(i);
		}
	}
}

void print_components()
{	int i,j;
	for(i=0;K>i;++i)
	{	printf("component %d :",1+i);
		for(j=I[i];I[i+1]>j;++j)
		{printf(" %d,%d ;",1+C[j].x,1+C[j].y);}
		printf(" #\n");
	}
}

void print_articulation_points()
{	printf("articulation points:");	
	int i,N=edges::N;
	for(i=0;N>i;++i)
	{	if(0!=A[i])
		{printf(" %d ;", 1+i);}
	}
	printf(" #\n");
}

}

// forest::process builds the forest with nodes
// biconnected and articulation points
namespace forest
{
int N; // number of vertices
int n; // vertices from 0..n-1 are components; from n to N-1 are articulation points
int V[2*maxn]; // vertices: 0<=V[i] : V[i] biconnected component; 0>V[i]: -V[i]-1 articulation
int E[2*maxn-1][2]; // edges (biconnected component, articulation point)
int A[2*(2*maxn-1)]; // adjacency lists

int I[2*maxn+1]; // A[j], I[x]<=j<=I[x+1]-1, x=0..2*maxn-1, adjacency list for V[x]
int J[2*maxn]; // J[x] - next free position in A for x

int L[maxn]; // Label articulation points;Label graph nodes in component nodes


void process()
{	N=0;
	int i,m,c,a,s,t,x,y;
	// build vertex set
	for(i=0;biconnected::K>i;++i){V[N++]=i;}
	n=N;
	for(i=0;edges::N>i;++i)
	{	if(biconnected::A[i]){V[N++]=i;}	}
	// build labels for articulation points
	for(i=0;edges::N>i;++i){L[i]=-1;}
	for(i=n;N>i;++i){L[V[i]]=i;}
	// build edge set
	m=0;
	for(i=0;n>i;++i)
	{	c=V[i];
		s=biconnected::I[c];
		t=biconnected::I[c+1];
		while(s<t)
		{	x=biconnected::C[s].x;
			y=biconnected::C[s].y;
			++s;
			if(-1!=L[x])
			{E[m][0]=c;E[m][1]=L[x];++m;}
			if(-1!=L[y])
			{E[m][0]=c;E[m][1]=L[y];++m;}
		}
	}
	// build adjacency lists
	for(i=0;N>i;++i){I[i]=0;}
	for(i=0;m>i;++i){++I[E[i][0]];++I[E[i][1]];}
	c=I[0];I[0]=0;for(i=1;N>=i;++i){a=I[i];I[i]=I[i-1]+c;c=a;}
	for(i=0;N>i;++i){J[i]=I[i];}
	for(i=0;m>i;++i){A[J[E[i][0]]++]=E[i][1];A[J[E[i][1]]++]=E[i][0];}
	// relabel to find graph nodes in component nodes
	for(i=0;edges::N>i;++i){L[i]=-1;}
	for(i=0;n>i;++i)
	{	c=V[i];
		s=biconnected::I[c];
		t=biconnected::I[c+1];
		while(s<t)
		{	x=biconnected::C[s].x;
			y=biconnected::C[s].y;
			++s;
			if(-1==L[x]){L[x]=c;}
			if(-1==L[y]){L[y]=c;}
		}
	}
}

// tree(forest) component node containing graph node x
int find_node(int x)
{	return L[x];
}

// tree component node contains graph node w?
bool contains(int c,int w)
{	int s,t,x,y;
	s=biconnected::I[c];
	t=biconnected::I[c+1];
	while(s<t)
	{	x=biconnected::C[s].x;
		y=biconnected::C[s].y;
		++s;
		if(x==w){return true;}
		if(y==w){return true;}
	}
	return false;
}

}

// For any 3 vertices x, y, and z in a biconnected component with 3 nodes or more
// there is a simple path from x to z through y.

// hamilton::process() searches for a hamiltonian path from node 0 to node Z
// node Z is what value Z contains if Z is positive, any node but 0 if Z is negative
namespace hamilton
{
int N;// number of vertices
int Z;// node Z
int A[maxc];// adjacency
int B[1<<maxc][maxc];// B[Y][x] - node before x on simple path from node 0 to node x through nodes Y

void process()
{	int t=(1<<N)-1,s,x,bx,y,by;
	for(s=0;t>=s;++s)
	{	for(x=0;N>x;++x)
		{B[s][x]=-1;}
	}
	for(x=1;N>x;++x)
	{	bx=(1<<x);
		if(A[0]&bx)
		{B[(1<<0)|bx][x]=0;}
	}
	for(s=3;t>=s;++s)
	{	for(x=1;N>x;++x)
		{	bx=(1<<x);
			if((0!=(s&bx))&&(-1!=B[s][x]))
			{	for(y=1;N>y;++y)
				{	by=(1<<y);
					if((0==(s&by))&&(0!=(A[x]&by)))
					{B[s|by][y]=x;}
				}
			}
		}
	}
}

int print_path(int*a)
{	int t,x,y,by,l,s,e,f,g;
	t=(1<<N)-1;
	for(y=1;N>y;++y)
	{	if((-1!=B[t][y])&&((-1==Z)||(Z==y)))
		{	l=0;s=t;
			while(0!=y)
			{	a[l++]=y;by=(1<<y);
				x=B[s][y];s=s^by;y=x;
			}
			a[l++]=0;
			// converse
			e=0;f=l-1;
			while(e<f)
			{	g=a[e];a[e]=a[f];a[f]=g;
				++e;--f;
			}
			return l;
		}
	}
	return 0;
}

};


namespace problem
{
int S;// start point for spiridusi
int E;// santa's house (end point for spiridusi)
int Q;// start point for max
int P[2*maxn];// parent for dfs in forest
bool sol;// solution
int ans[maxn]; // the reunion of hamiltonian paths
int len; // the length of ans so far
int L1[maxn];// label 1
int L2[maxc];// label 2

void read_data()
{	freopen("santa.in","r",stdin);
	int i;
	scanf("%d %d",&(edges::N),&(edges::M));
	for(i=0;edges::M>i;++i)
	{	scanf("%d %d",&(edges::E[i].x),&(edges::E[i].y));
		--edges::E[i].x;--edges::E[i].y;
	}
	scanf("%d %d %d",&S,&E,&Q);
	--S;--E;--Q;
}

void build_hamilton_path_problem(int v,int c,int w)
{	// build labelings, compute node count
	c=forest::V[c];	
	int i1=biconnected::I[c],i2=biconnected::I[c+1],i,t,x,y,f;
	edge*C=biconnected::C;
	i=i1;t=i2;
	while(i<t)
	{	x=C[i].x;y=C[i].y;++i;
		L1[x]=L1[y]=-1;
	}
	f=0;
	L1[v]=f;L2[f]=v;++f;//0
	if(-1!=w)
	{	L1[w]=f;L2[f]=w;++f;
		w=1;
	}
	i=i1;t=i2;
	while(i<t)
	{	x=C[i].x;y=C[i].y;++i;
		if(-1==L1[x]){L1[x]=f;L2[f]=x;++f;}
		if(-1==L1[y]){L1[y]=f;L2[f]=y;++f;}
	}
	hamilton::N=f;
	hamilton::Z=w;
	// build adjacency
	for(x=0;f>x;++x){hamilton::A[x]=0;}
	i=i1;t=i2;
	while(i<t)
	{	x=L1[C[i].x];y=L1[C[i].y];++i;
		hamilton::A[x]|=(1<<y);
		hamilton::A[y]|=(1<<x);
	}
}

void relabel_hamiltonian_path(int l1)
{	int i=len,t=len+l1;
	while(i<t)
	{ans[i]=L2[ans[i]];++i;}
	len+=l1;
}

void DFS(int x)
{	int i=forest::I[x],t=forest::I[x+1],y;
	while(i<t)
	{	y=forest::A[i++];
		if(-1==P[y])
		{P[y]=x;DFS(y);}
	}
}

// The component where santa is.
int find_e_node(int s)
{	int e,x,o;	
	e=forest::find_node(E);
	// Unique path in tree between.
	for(x=0;forest::N>x;++x){P[x]=-1;}
	P[e]=e;DFS(e);	
	// Not reachable.
	if(-1==P[s])
	{return -1;}
	// Move closer.
	o=s;
	while(s!=e)
	{	o=s;
		s=P[s];//articulation
		s=P[s];//2-component
	}
	if(forest::contains(forest::V[o],E))
	{e=o;}
	
	return e;
}

void solve()
{	if((S==E)&&(Q==E))
	{	ans[0]=S;len=1;
		sol=true;
		return;
	}
	edges::init();
	biconnected::process();
	forest::process();
	sol=false;
	int s,e,x,c,y,l;
	s=forest::find_node(S);
	if(!forest::contains(s,Q))
	{	x=S;S=E;E=x;
		s=forest::find_node(S);
		if(!forest::contains(s,Q))
		{return;}
	}
	e = find_e_node(s);
	if(-1==e)
	{return;}
	// Find hamiltonian paths.
	x=Q;c=s;len=0;
	do
	{	y=((c==e)?(-1):(forest::V[P[c]]));
		build_hamilton_path_problem(x,c,y);
		hamilton::process();
		len=(0<len)?(len-1):0;//last equals first
		l=hamilton::print_path(&ans[len]);
		if(0==l)
		{return;}
		relabel_hamiltonian_path(l);
		c=(c==e)?(-1):(P[P[c]]);x=y;
	} while(-1!=c);
	
	sol=true;
}

void write_data()
{	//biconnected::print_components();
	//biconnected::print_articulation_points();
	freopen("santa.out","w",stdout);
	if(!sol)
	{printf("No chance\n");return;}
	printf("%d\n",len);
	int i;printf("%d",1+ans[0]);
	for(i=1;len>i;++i){printf(" %d",1+ans[i]);}
	printf("\n");
}

}

int main()
{	problem::read_data();
	problem::solve();
	problem::write_data();
	return 0;
}