拓扑排序入门

话不多说,先上图!!!

聪明的你,可以发现每次都是先输出入度为0的点(类似于入口),然后删除与此点相关的边,然后继续同样的操作。经过如此反复操作,如果图中的点都输出了,就说明此图是无环有向图,否则就是有环图。

比如说这里的环CED,BD,环中任意一点入度都不为0,根本找不到入口。所以没法遍历完所有的点

对于题目给定了众多两点之间的优先级关系,然后让你判断所有点之间的是否构成优先级。

  • 现在来介绍一个模板题
有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。 

Input输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。 
Output给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。 

其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。 

  • Sample Input
4 3
1 2
2 3
4 3
  • Sample Output
1 2 4 3

简单来说,存图时需要记录每个点的入度数(用数组),以及记录一个出度邻接表(vector)。把入度为0的点都放入到队列中。队列每出队一个,就将此点出度相连的点入度-1,减的过程中,又出现了入度为0点的时候,再把入度为0的点加入到队列。

最后遍历一遍入度数的数组,若数组中全入度为0,则图遍历完毕,不存在环,否则肯定存在环。

#include <bits/stdc++.h>
using namespace std;
const int NN = 550;

int in[550];//in[i]:点i的入度次数 
int N,M;
int main(){
    while(cin>>N>>M){
        vector<int> out[550];//out[i]:点i出度相连的点 
        priority_queue<int, vector<int>, greater<int> > q;//优先队列,从小到大排列 
        memset(in,0,sizeof(in));
        int win,lo; //赢 输 
        for(int i = 1;i<=M;i++){
            scanf("%d%d",&win,&lo);
            out[win].push_back(lo); //以赢->输的关系存储的 
            in[lo]++;//谁输了,谁的入度+1 
        }
        for(int i = 1;i<=N;i++){ //将入度为0的点加入到优先队列 
            if(in[i] == 0)
                q.push(i);
        }
        int tag = 0;//题目要求,末尾不加空格 
        while(!q.empty()){
            int x = q.top();
            q.pop();//删除入度为0的点 
            if(tag)
                cout<<" ";
            tag = 1;
            cout<<x;
            for(int i = 0;i<out[x].size();i++){ //将x出度相连的点入度-1,相当于删除边 
                    in[out[x][i]]--;
                    if(in[out[x][i]] == 0){//某点度为0,就加入到优先队列中 
                        q.push(out[x][i]);
                    }
            }
        }
        cout<<endl;
        
    }
    
    return 0;
}
原文地址:https://www.cnblogs.com/bigbrox/p/11316059.html