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.

转载于:https://www.cnblogs.com/Thispoet/archive/2011/10/18/2216623.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值