拓扑排序

初学:

 常用来表示事件之间的依赖关系,任务之间的调度

典型:依赖处理

在图论上,他是把DAG生成一个线性数列,表示这个图顶点之间的先后关系

过程

  1. 建立一个空队列,把所有入度为 0 的加入队列
  2. 然后从队列中取出一个节点,把该节点所有的出边删除,即入度 -1, 再判断该边通向的节点是否已经没有边连入(即入度是否为 0 ),若是,加入队列
  3. 重复,直到队列中不剩下任何节点

注:拓扑排序是对于DAG而言。如果需要判断图中是否存在环, 可以统计是否所有的节点都入过队。存在未入队的节点,代表存在环(无法拓扑排序) (因为入度不可能为0

 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 #define MAXN 1111
 5 #define MAXM 121111
 6 
 7 int n, m, cnt;
 8 int head[MAXN], q[MAXN], ru[MAXN];
 9 
10 struct edge {
11     int y, next;
12 }e[MAXM];
13 
14 void add_edge(int x, int y) {
15     e[++cnt].y = y;
16     e[cnt].next = head[x];
17     head[x] = cnt;
18     return ;
19 }
20 
21 int main() {
22     scanf("%d%d", &n, &m);
23     for(int i = 1; i <= m; i++) {
24         int x, y;
25         scanf("%d%d", &x, &y);
26         ru[y]++;
27         add_edge(x, y);
28     }
29     int l = 1, r = 0;
30     for(int i = 1; i <= n; i++) {//入队 
31         if(!ru[i]) {
32             r++;
33             q[r] = i;
34         }
35     }
36     while(l <= r) {//一直while到q里没元素 
37         int now = q[l];
38         l++;//首元素出队
39         for(int i = head[now]; i; i = e[i].next) {
40             int y = e[i].y;
41             ru[y]--;//终点为y的线段 入度——
42             if(!ru[y]) {//如果入度减到了零 ,就让它进队(从后面入) 
43                 q[++r] = y;
44             }
45         }
46     }
47     for(int i = 1; i <= m; i++) printf("%d ", q[i]);//队列前m个是已经拓扑排序好了的元素 
48     return 0;
49 }

另一种亲民的做法(STL大法好,真善...

int n,m;
queue <int> q;
for(int i = 1; i <= n; i++) if(ru[i] == 0) q.push(i);
vector<int> ans;
while(!q.empty()) {
    int u = q.front() ; q.pop() ;
    ans.push_back(u);
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        ru[v]--;
        if(ru[v] == 0) {
            q.push(v); 
        }
    } 
}
 if(ans.size()==n) {
    for(int i=0;i<ans.size();i++)
        printf( "%d ",ans[i] );
        printf("
");
    } else printf("No Answer!
");   
    // ans 中的长度与n不相等,就说明无拓扑序列

相关题目

1. 要求字典序最小

解决方法: 改为优先队列即可

                2153: D.ly的排队问题
            Time Limit: 1 Sec  Memory Limit: 128 MB

Description
马上要上体育课了,上体育课之前总归是要排个队的,ly作为班长,怎么排队的问题只能由她来解决,但是马上要上课了,ly又不清楚所有人的身高,她又不好意思问每个人的身高,因为这样会显的自己很不负责,于是她只能通过肉眼观察...那么问题来了,她只能观察出两个人A和B谁高谁矮,但是她没有办法排出一个序列。
ly都已经帮你出了两次主意赢过wjw,那么现在她需要你的帮助,你可以帮她吗?
(ly会告诉你A和B谁高,如果A比B高,会用A>B来表示)

Input
只有一组数据,每个比较结果占一行,读取到文件结束

Output
若输入数据无解,则输出"No Answer!",否则从高到低输出每个人的名字,中间没有分割符
若有多种情况,输出字典序最小的答案

Sample Input
E>A
A>S
S>Y
Sample Output
EASY

注: 这里的目的只是引入字典序最小该怎么做,具体的题解实际上是有点问题的

如: A>B B<C C<D 结果实际上是判断不出身高的(阔以自己试试

#include<cstdio>
#include<queue>
#include<set>
#include<vector>
#include<iostream>
using namespace std;


int main() {
    set <int> s;
    int ru[30] = {0};
    vector <int> v[30];
    char tmp[5];
//    while(cin>>tmp) {
    while(~scanf("%s",tmp)) {
        s.insert(tmp[0]-'A');
        s.insert(tmp[2]-'A');
        if(tmp[1] == '>') {
            ru[tmp[2]-'A']++;
            v[tmp[0]-'A'].push_back(tmp[2]-'A'); 
        } else {
            ru[tmp[0]-'A']++;
            v[tmp[2]-'A'].push_back(tmp[0]-'A'); 
        }
    }
    priority_queue <int,vector<int>,greater<int> > q;
    for(int i = 0; i < 30; i++) if(ru[i]==0 && s.count(i) != 0) q.push(i);
    vector <int> ans;
    while(!q.empty()) {
        int now = q.top() ; q.pop() ;
        ans.push_back(now); 
        for(int i = 0; i < v[now].size() ; i++) {
            int y = v[now][i];
            ru[y]--;
            if(ru[y] == 0&&s.count(y)!=0) q.push(y); 
        }
    }
    if(ans.size() != s.size() ) printf("No Answer!");
    else for(int i = 0; i < ans.size() ; i++) printf("%c",ans[i]+'A');
    printf("
");
    return 0;
} 
/*
A>B
B<C
C<D
*/

 

 参考代码

自己选择的路,跪着也要走完。
原文地址:https://www.cnblogs.com/tyner/p/10701729.html