第三道tarjan,有了前两道题的经验,很快就写完了,但是万恶的初始化。。。。。。
题目大意如下:给出若干个测试样例,当奇数行的N不为0时,有两个数N,M,代表有N个点M条边,然后偶数行会有M条边的信息,求出每个数据里缩点后出度为0的所有点,把所有这些点集里的点标记后按升序输出,如果N=0则结束程序。其中1<=n,m<=5000
不想解释太多,这道题还是比较水的,关键是要在输出时把所有的点进行升序输出而并非对于每个强连通分量。
要注意初始化,其实本来可以1A的,就是没有注意初始化,然后各种爆时间爆空间爆栈。。。。。。
var
g:array[1..6000,1..6000] of 0..1;
f,v,wr:array[1..6000] of boolean;
dfn,low:array[1..6000] of integer;
stack:array[1..6000] of integer;
sd,cd:array[1..6000] of integer;
n,m,i,x,y,deep,top,ans,j:integer;
function min(a,b:integer):integer;
begin
if a<b then exit(a) else exit(b);
end;
procedure pop(k:integer);
begin
while stack[top+1]<>k do
begin
sd[stack[top]]:=ans; //缩点
f[stack[top]]:=false;
dec(top);
end;
end;
procedure dfs(k:integer);
var
i:integer;
begin
inc(deep);
dfn[k]:=deep; low[k]:=deep;
inc(top);
stack[top]:=k;
v[k]:=true; f[k]:=true;
for i:=1 to n do
begin
if g[k,i]=1 then
begin
if v[i]=false then
begin
dfs(i);
low[k]:=min(low[k],low[i]);
end
else
if f[i] then low[k]:=min(low[k],dfn[i]);
end;
end;
if dfn[k]=low[k] then begin inc(ans); pop(k); end;
end;
begin
read(n);
while n<>0 do
begin
read(m);
fillchar(g,sizeof(g),0);
fillchar(wr,sizeof(wr),false);
fillchar(v,sizeof(v),false);
fillchar(f,sizeof(f),false);
fillchar(sd,sizeof(sd),0);
fillchar(cd,sizeof(cd),0);
fillchar(stack,sizeof(stack),0);
fillchar(dfn,sizeof(dfn),0);
fillchar(low,sizeof(low),0);
ans:=0; deep:=0; top:=0; //记得初始化,最后这一行坑了我10几次提交
for i:=1 to m do
begin
read(x,y);
g[x,y]:=1;
end;
for i:=1 to n do
if v[i]=false then dfs(i); //Tarjan
for i:=1 to n do
for j:=1 to n do
if (g[i,j]=1) and (sd[i]<>sd[j]) then inc(cd[sd[i]]); //记录出度
for i:=1 to ans do
if cd[i]=0 then
for j:=1 to n do
if sd[j]=i then wr[j]:=true; //标记出度为0的所有点集的所有点
for i:=1 to n do if wr[i]=true then write(i,' ');
writeln;
read(n);
end;
end.
其实用矩阵的时间和空间复杂度会比较高,时间和空间都只是刚刚好卡点而已,链接表有些细节的地方还在改,但是矩阵相对比较容易理解额。。。。。。