【专题】拓扑排序 入门版

来源:互联网 发布:网络电视怎样看中央台 编辑:程序博客网 时间:2024/06/01 15:47

(注:如果你是提高组+的大牛,敬可忽略本文 谢谢合作)

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

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

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

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

先搬出来一道例题:

2历史事件

【问题描述】

一些历史迷们打算把历史上的一些大事件按时间顺序列出来。但是,由于资料不全,每个事件发生的具体时间都没有找到。幸运的是,他们记得一些事件之间的先后关系。他们把事件分别编号123,……n,然后把一些先后关系列出。不过,这些复杂的先后关系仍然把他们难倒了。你能够帮助他们吗?

【输入文件】

输入文件event.in。第一行是两个整数nm1<=n<=10001<=m<=100000),分别表示事件数和已知的先后关系数。接下来m行,第i行是两个整数xiyi1<=xiyi<=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>
还有,数据好坑,输入还有重复的情况。。。。。(逗我吗)

1 0
原创粉丝点击