所谓拓扑序列,就是有向图的最长路径问题,如果图中存在环,则最长路径是无法求得的,所以有拓扑序列的有向图不可以存在环。具体定义如下:
给出有向图G=(V,E),若结点的线形序列V1,V2,...Vn满足条件:对于i,j(1≤j<i≤n),Vi和Vj之间没有边。求线形序列V1,V2,...Vn的过程就称为拓扑排序,这个线形序列就称为拓扑序列。
【拓扑排序主要思想】
有向图可以拓扑排序的条件是:图中没有环。
具体方法:
⑴ 从图中选择一个入度为0的点加入拓扑序列。
⑵ 从图中删除该结点以及它的所有出边(即与之相邻点入度减1)。
反复执行这两个步骤,直到所有结点都已经进入拓扑序列。
【实例:士兵排队问题】
有n个士兵(1≤n≤26),依次编号为A,B,C,...,队列训练时,指挥官要把一些士兵从高到矮排成一行。但现在指挥官不能直接获得每个人的身高信息,只能获得“p1比p2高”这样的比较结果,记作(p1>p2)。例如A>B,B>D,F>D,对应的排队方案有三个:AFBD,FABD,ABFD
【输入】
k行,每行a b,表示a>b
【输出】
一个可行的排队方案
【输入样例】 A B
B D F D 【输出样例】
ABFD
|
program soldier_sort;
var
w:array['A'..'Z','A'..'Z'] of 0..1;
d:array['A'..'Z'] of integer; {记录顶点入度的数组}
s:set of 'A'..'Z';
a,b,ch:char;
m,n:string;
i,j,k:integer;
begin
assign(input,'tuopu.in');
reset(input);
assign(output,'tuopu.out');
rewrite(output);
s:=[];
while not eof(input) do
begin
readln(a,ch,b);
s:=s+[a,b]; {计算士兵名集合}
w[a,b]:=1;
d[b]:=d[b]+1; {累计顶点b的入度}
end;
m:='';
for a:='A' to 'Z' do
if a in s
then m:=m+a; {产生士兵名字符集}
k:=length(m); {求得士兵人数}
n:=''; {拓扑序列初始为空}
for i:=1 to k do
begin
j:=1;
while (d[m[j]]>0) and (j<=k) do {搜索第i个入度为0的士兵的顶点序号j}
j:=j+1;
if j>k {若不存在入度为0的顶点,则无法拓扑排序失败}
then begin
writeln('Fault!');
break;
end;
n:=n+m[j]; {入度为0的顶点进入拓扑序列n}
a:=m[j]; {删去顶点j}
d[a]:=maxint;
for j:=1 to k do {与a相连的顶点入度减1}
if w[a,m[j]]>0
then d[m[j]]:=d[m[j]]-1;
end;{for}
writeln(n);
close(input);
close(output);
end.