Cod sursa(job #528785)

Utilizator mgntMarius B mgnt Data 3 februarie 2011 14:25:24
Problema Santa Scor 90
Compilator cpp Status done
Runda Arhiva de probleme Marime 10.94 kb
#include <cstdio>
#include <cstdlib>
#include <cstring>
#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(-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[x]>D[y])&&(y!=P[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;
	printf("%d components!\n",K);
	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
int F[maxn]; // articulation point is free to add edge to for current component!

void process()
{	N=0;
	int i,j,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];
		for(j=n;N>j;++j){F[V[j]]=1;}
		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])
			{	if(F[x])
				{E[m][0]=c;E[m][1]=L[x];++m;F[x]=0;}
			}
			if(-1!=L[y])
			{	if(F[y])
				{E[m][0]=c;E[m][1]=L[y];++m;F[y]=0;}
			}
		}
	}
	// 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];}
}

void print()
{	int i,x,t,y;
	printf("Forest of biconnected components\n");
	printf("%d component vertices, %d graph vertices\n",n,N-n);
	printf("Component vertices:");for(i=0;n>i;++i){printf(" %d",V[i]);}printf("\n");
	printf("Graph vertices:");for(i=n;N>i;++i){printf(" %d",V[i]);}printf("\n");
	printf("Adjacency lists:\n");
	for(x=0;N>x;++x)
	{	printf("adj[%d]:",x);
		i=I[x];t=I[x+1];while(i<t){y=A[i++];printf(" %d",y);}
		printf("\n");
	}
}

// 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 V;// start
int L[maxc];// neighbour of start
int F[maxc];// neighbour of Z?
int Z;// node Z
int VZ;// edge between V and Z?
int A[maxc][maxc+1];// adjacency
signed char B[(1<<maxc)*maxc];// B[Y][x] - node before x on simple path from node 0 to node x through nodes Y
int Q[(1<<maxc)*maxc]; // queue s,x updates

void process()
{	int i,d,t,mdl,msk,s,x,bx,y,by,qi,qo,sx,sy;
	mdl=(1<<N);msk=mdl-1;
	
	t=mdl*N;
	memset(B,0xff,t*sizeof(B[0]));// for(i=0;t>s;++s){B[i]=-1;}
	
	d=L[0];qi=qo=0;
	for(i=1;d>=i;++i)
	{	x=L[i];bx=(1<<x);sx=bx+x*mdl;
		B[sx]=-3;Q[qi++]=sx;
	}
	
	while(qo<qi)
	{	sx=Q[qo++];
		s=(sx&msk);//s=sx%mdl;
		x=(sx>>N); //x=sx/mdl;
		d=A[x][0];
		for(i=1;d>=i;++i)
		{	y=A[x][i];by=(1<<y);
			if(0==(s&by))
			{	sy=(s|by)|(y<<N);//sy=(s|by)+y*mdl;
				if(-1==B[sy])
				{B[sy]=x;Q[qi++]=sy;}
			}
		}
	}
}

int print_path(int*a)
{	int t,mdl,x,y,by,l,s,e,f,g,sy;
	t=(1<<N)-1;mdl=(1<<N);
	for(y=0;N>y;++y)
	{	sy=t+y*mdl;
		if((-1!=B[sy])&&((-4==Z)||F[y]))
		{	if(-4!=Z){a[0]=-4;l=1;}else{l=0;}
			s=t;
			while(-3!=y)
			{	a[l++]=y;by=(1<<y);sy=s+y*mdl;
				x=B[sy];s=s^by;y=x;
			}
			a[l++]=-3;
			// converse
			e=0;f=l-1;
			while(e<f)
			{	g=a[e];a[e]=a[f];a[f]=g;
				++e;--f;
			}
			return l;
		}
	}
	if(0==N)
	{	if(VZ)
		{	a[0]=-3;a[1]=-4;
			return 2;
		}
	}
	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,bs;
	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;
	}
	hamilton::V=v;
	L1[v]=-3;v=-3;
	if(-1!=w)
	{hamilton::Z=w;L1[w]=-4;w=-4;}
	else
	{w=-4;hamilton::Z=w;}
	f=0;
	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;
	// build adjacency
	for(x=0;f>x;++x){hamilton::A[x][0]=0;}
	for(x=0;f>x;++x){hamilton::F[x]=0;}
	hamilton::L[0]=0;bs=0;
	hamilton::VZ=0;
	i=i1;t=i2;
	while(i<t)
	{	x=L1[C[i].x];y=L1[C[i].y];++i;
		if((0<=x)&&(0<=y))
		{	hamilton::A[x][++hamilton::A[x][0]]=y;
			hamilton::A[y][++hamilton::A[y][0]]=x;
		}
		else
		{	if((-3==x)&&(0<=y)&&(0==(bs&(1<<y))))
			{hamilton::L[++hamilton::L[0]]=y;bs|=(1<<y);}
			if((-3==y)&&(0<=x)&&(0==(bs&(1<<x))))
			{hamilton::L[++hamilton::L[0]]=x;bs|=(1<<x);}
			if((-4==x)&&(0<=y)){hamilton::F[y]=1;}
			if((-4==y)&&(0<=x)){hamilton::F[x]=1;}
			if((-4==y)&&(-3==x)){hamilton::VZ=1;}
			if((-4==x)&&(-3==y)){hamilton::VZ=1;}
		}
	}
}

void relabel_hamiltonian_path(int l1)
{	int i=len,t=len+l1;
	while(i<t)
	{	if(0<=ans[i])
		{ans[i]=L2[ans[i]];}
		else
		{	if(-3==ans[i])
			{ans[i]=hamilton::V;}
			else
			{	if(-4==ans[i])
				{ans[i]=hamilton::Z;}
			}
		}
		++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);}
	}
}

// helpers
int find_s_node()
{	int c,t;
	// Max moves from helpers to santa.
	for(c=0;forest::n>c;++c)
	{	if(forest::contains(c,S))
		{	if(forest::contains(c,Q))
			{	return c;	}
		}
	}
	// Max moves from santa to helpers.
	// swap santa with helpers.
	t=S;S=E;E=t;
	for(c=0;forest::n>c;++c)
	{	if(forest::contains(c,S))
		{	if(forest::contains(c,Q))
			{	return c;	}
		}
	}
	return -1;
}

// The first guess for where santa is.
int find_e_node_estimate()
{	int c;
	for(c=0;forest::n>c;++c)
	{	if(forest::contains(c,E))
		{return c;}
	}
	return -1;
}

// The component where santa is.
int find_e_node(int s)
{	int e,x,o;
	e=find_e_node_estimate();
	if(-1==e)
	{return -1;}
	// 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 print_dfs()
{	printf("DFS!\n");
	int i;
	for(i=0;forest::N>i;++i)
	{printf("P[%d]=%d; ",i,P[i]);}
	printf("\n");
}

//#define VERBOSE

void solve()
{	if((S==E)&&(Q==E))
	{	ans[0]=S;len=1;
		sol=true;
		return;
	}
	edges::init();
	biconnected::process();
	forest::process();
	#ifdef VERBOSE
	biconnected::print_components();
	biconnected::print_articulation_points();
	forest::print();
	#endif
	sol=false;
	int s,e,x,c,y,l;
	s=find_s_node();
	if(-1==s)
	{return;}
	e=find_e_node(s);
	#ifdef VERBOSE
	print_dfs();
	#endif
	if(-1==e)
	{return;}
	// Find hamiltonian paths.
	if(Q==forest::V[P[s]])
	{	len=1;ans[0]=Q;s=P[P[s]];// Move to entry in next component!
		if((S!=Q)&&(s!=e))
		{return;}
	}
	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()
{	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;
}