POJ2186——并查集+Tarjan算法求强连通分量

算法讨论:这题陷阱比较多。首先,被所有牛欢迎,这说明所有的牛都要在一个连通图中,也就是将所给的边看成无向边的时候,所有点要在一个连通图中。这个我们用并查集来实现就可以了。强连通分量的求法就很简单了,正常的Tarjan就好了。求完强连通分量之后重新建图,找出新图上出度为0的点,那么在原图上在这个强连通分量中的点的个数就是答案。

我的代码:

program popular;//By_Thispoet

const

	maxn=10005;

var

	i,j,k,m,n,p,q,total,time,size	:longint;

	pr,la,ot,pre,other,last			:array[0..maxn*5]of longint;

	stack,father					:array[0..maxn]of longint;

	color,dfn,low,num				:array[0..maxn]of longint;

	outo							:array[0..maxn]of longint;

	

function min(i,j:longint):longint;

begin

	if i<j then exit(i);exit(j);

end;



function root(i:longint):longint;

begin

	if father[i]=i then exit(i);

	father[i]:=root(father[i]);

	exit(father[i]);

end;



procedure union(i,j:longint);

var x,y:longint;

begin

	x:=root(i);y:=root(j);

	father[x]:=y;

end;



procedure deal(i:longint);

begin

	inc(total);

	while stack[size]<>i do

		begin

			color[stack[size]]:=total;

			inc(num[total]);

			dec(size);

		end;

	color[i]:=total;

	inc(num[total]);

	dec(size);

end;



procedure tarjan(i:longint);

var j,k:longint;

begin

	inc(time);

	dfn[i]:=time;low[i]:=time;

	inc(size);stack[size]:=i;

	j:=la[i];

	while j<>0 do

		begin

			k:=ot[j];

			if dfn[k]<>-1 then

				low[i]:=min(low[i],dfn[k]) else

					begin

						tarjan(k);

						low[i]:=min(low[i],low[k]);

					end;

			j:=pr[j];

		end;

	if low[i]=dfn[i] then deal(i);

end;



procedure prepare;

begin

	k:=0;

	for i:=1 to n do 

		begin

			j:=la[i];p:=color[i];

			while j<>0 do 

				begin

					q:=color[ot[j]];

					if p<>q then inc(outo[p]);

					j:=pr[j];

				end;

		end;

end;

	

begin

	readln(n,m);

	fillchar(num,sizeof(num),0);

	fillchar(la,sizeof(la),0);

	for i:=1 to n do father[i]:=i;

	for i:=1 to m do

		begin

			readln(p,q);

			union(p,q);

			inc(k);pr[k]:=la[p];la[p]:=k;ot[k]:=q;

		end;

	for i:=1 to n do if root(i)<>root(1) then 

		begin

			writeln(0);

			halt;

		end;

	fillchar(dfn,sizeof(dfn),255);

	for i:=1 to n do

		if dfn[i]=-1 then tarjan(i);

	prepare;

	p:=0;q:=0;

	for i:=1 to total do 	

		if outo[i]=0 then

			begin

				inc(p);

				q:=i;

			end;

	if p=1 then writeln(num[q]) else writeln(0);

end.

你可能感兴趣的:(tar)