您的位置:首页 > 其它

【专题】拓扑排序 入门版

2016-03-09 13:06 295 查看
(注:如果你是提高组+的大牛,敬可忽略本文 谢谢合作)

拓扑排序(标题一定要大大大~~~)

耙耙说,要先把概念搬出来:对一个有向无环图(Directed
Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。


(这么不要脸的从百度百科搬来真的好吗。。。)、

好吧,其实你只要知道,什么是有向无环图,就够了。。。(逗我呢)

先搬出来一道例题:

题2历史事件
【问题描述】
一些历史迷们打算把历史上的一些大事件按时间顺序列出来。但是,由于资料不全,每个事件发生的具体时间都没有找到。幸运的是,他们记得一些事件之间的先后关系。他们把事件分别编号1,2,3,……n,然后把一些先后关系列出。不过,这些复杂的先后关系仍然把他们难倒了。你能够帮助他们吗?
【输入文件】
输入文件event.in。第一行是两个整数n,m(1<=n<=1000,1<=m<=100000),分别表示事件数和已知的先后关系数。接下来m行,第i行是两个整数xi,yi(1<=xi,yi<=n),表示事件xi比事件yi先发生。
【输出文件】
输出文件event.out。按事件发生的时间顺序列出事件的编号,每行一个,若存在多种可能,输出第一个事件编号最小的,若第一个事件编号相同,则输出第二个事件编号最小的……;若没有满足条件的编号序列,输出一行’Error!’)。
【样例输入】
3 2
1 2
1 3
【样例输出】
1
2
3
这题真的是纯拓扑纯拓扑纯拓扑(重要的事情说三遍)

实际上,题目的意思就是拓扑的作用、原理吧。。。






以上图为例(请勿吐槽)先说明一些东西:

入度:即有多少条边指向某个顶点(有向图) 例如上图中顶点2的入度为2

出度:即某个顶点向外指向的边有多少条 例如上图中顶点2的出度为1

每一次,选一个入度为 0 的顶点输出(如上图顶点1),然后将其所有后继顶点的入度-1(即把这个顶点往外伸展的边删除),重复这两步直至输出所有顶点,或找不到入度为 0 的顶点为止(这就是有“环”的情况)


上面的例子排序后的序列为0 1 2 4 3 5 7 8 (自己演算去)

找到一个入度为0的点并处理完后,再重新从1到n找(越小越好)

<span style="font-size:14px;color:#330033;">var n,m,i,x,y,t,j,k:longint;
rd,cd,b,c:array[1..1001] of longint;
f:array[1..1001,1..1001] of longint;
p:boolean;

{procedure tuopu;
var i,j:longint;
p:boolean;
begin
p:=false;
for i:=1 to n do begin
if rd[i]=0 then begin
p:=true;
rd[i]:=-1;
for j:=1 to n do begin
if (f[i,j]=1)and(i<>j) then begin
f[i,j]:=0;
dec(rd[j]);
end;
end;
inc(t);
c[t]:=i;
end;
end;
if not p then begin
writeln('Error!');
halt;
end;
end;} (请忽略此段,错误打法)

procedure ex;
begin
writeln('Error!');
close(input);
close(output);
halt;
end;

begin
assign(input,'event.in');reset(input);
assign(output,'event.out');rewrite(output);
readln(n,m);
for i:=1 to m do begin
readln(x,y);
if f[x,y]=1 then continue;
f[x,y]:=1;
inc(rd[y]);
end;
i:=0;
while i<n do begin
p:=false;
j:=1;
for k:=1 to n do if rd[k]=0 then begin (判断是否有环)
p:=true;
break;
end;
if not p then ex;
while rd[j]<>0 do inc(j);(找入度为0的点)
rd[j]:=-1;
for k:=1 to n do if f[j,k]=1 then begin
dec(rd[k]);
f[j,k]:=0;
end;(处理)
inc(i);
c[i]:=j;
end;
for i:=1 to n do writeln(c[i]);
close(input);
close(output);
end.</span><span style="color:#003366;font-size:18px;">
</span>还有,数据好坑,输入还有重复的情况。。。。。(逗我吗)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息