问题
给定多组数据,每组数据中有多个大小关系,让你判断是否能产生一个拓扑序列,如果可以,输出在第几个关系之后得到,并输出这个序列。如果不可以,输出在第几个关系之后无解;如果存在多解,按题目要求输出。
分析
就是拓扑排序,加队列优化,再加一点改进。每次读入关系之后进行拓扑排序。我们知道,如果一个序列能得到拓扑排序的序列,那么在每步有且仅有一个节点的入度为0,如果不存在入度为零的点,则无解。如果入度为零的点的个数多于一个,则存在多解。
对于队列拓扑排序的原理我们了解,每次选取队首元素是,判断当前队伍中元素的个数,如果多于一个,暂时标记多解(可能在后面的过程中出现无解)。那么什么时候队列中不在有元素捏?就是停止while循环的时候,所以我们只需在最后判断是否生成一个长度为n的序列即可(如果存在多解,同样可以生成,想想为什么)。
code
program liukee;
var
a:array[1..50,0..50] of longint;
into,into1:array[1..50] of longint;
ans:array[1..1000] of longint;
n,m,i,x,y,turn,temp,j:longint;
flag:boolean;
ch1,ch2,kong:char;
function spfa:longint;
var
l,r,now,sum,i,tt:longint;
q:array[1..100000] of longint;
begin
spfa:=1;
fillchar(q,sizeof(q),0);
fillchar(ans,sizeof(ans),0);
l:=0;
r:=0;
tt:=0;
for i:=1 to n do
if into1[i]=0 then
begin
inc(r);
q[r]:=i;
end;
while l<r do
begin
sum:=r-l;
if sum>1 then spfa:=-1;
inc(l);
now:=q[l];
inc(tt);
ans[tt]:=now;
for i:=1 to a[now,0] do
begin
dec(into1[a[now,i]]);
if into1[a[now,i]]=0 then
begin
inc(r);
q[r]:=a[now,i];
end;
end;
end;
if tt<n then exit(0);
end;
begin
readln(n,m);
while (n<>0)and(m<>0)do
begin
flag:=false;
fillchar(a,sizeof(a),0);
fillchar(into,sizeof(into),0);
turn:=0;
for i:=1 to m do
begin
inc(turn);
read(ch1);
x:=ord(ch1)-64;
read(kong);
read(ch2);
readln;
y:=ord(ch2)-64;
inc(a[x,0]);
a[x,a[x,0]]:=y;
inc(into[y]);
if flag then continue;
into1:=into;
temp:=spfa;
if temp=1 then begin write('Sorted sequence determined after ',turn,' relations: ');flag:=true; for j:=1 to n do write(chr(ans[j]+64)); end
else if temp=0 then begin write('Inconsistency found after ',turn,' relations');flag:=true;end;
end;
if not flag then write('Sorted sequence cannot be determined');
readln(n,m);
write('.');
writeln;
end;
end.
反思
对经典算法的改进一定是建立在对算法的深刻理解之上!