拓扑排序
定义:
将有向无环图的顶点排成一个线性序列,使得任一点有通路能通向其后的所有点
方法:
(1) 选择一个入度为0的顶点并输出之;
(2) 从网中删除此顶点及所有出边。
例题:
Problem Description
有N个比赛队(1<=N<=500),编号依次为1,2,3,。。裁判委员仅仅知道每场比赛的结果。即P1赢P2,用P1。P2表示。如今请你编程序确定排名;
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
#define maxn 1005
const int inf=0x3f3f3f3f;
typedef long long ll;
vector<int>v[maxn];//邻接列表
int f[maxn],g[maxn],a[maxn];
int x,t,y,n,m;
void topo(){
for(int i=1;i<=n;i++){
t=1;
while(f[t]!=0) t++; //找第一个入度为0的点
g[i]=t;//存储输出的顺序
f[t]--; //找到第一个入度为0的点后将该点入度标记为-1
for(int j=0;j<v[t].size();j++) f[v[t][j]]--; //这一步相当于删除这个点
//即让与他邻接的点入度都减一
}
for(int i=1;i<=n;i++){
if(i!=n) printf("%d ",g[i]);
else printf("%d\n",g[i]);
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
memset(f,0,sizeof f);
for(int i=1;i<=n;i++) v[i].clear();
while(m--){
scanf("%d%d",&x,&y);
f[y]++; //表示每个点的入度
v[x].push_back(y); //存储当前点邻接的点
}
topo();
}
return 0;
}
在保持拓扑顺序不变的情况下如何节省每次寻找第一个入度为0的时间:建立一个优先队列,将每次发现入度为零的值入队,并使点值小的点优先出队;
void topo(){
priority_queue<int,vector<int>,greater<int>> q;
for(int i=1;i<=n;i++) if(in[i]==0) q.push(i); //入度为0的点
int cnt=0;
while(!q.empty()){
int u=q.top();
q.pop();
ans[++cnt]=u;
for(int i=0;i<v[u].size();i++)//将与u连接的入度减-1
{
int e=v[u][i];
in[e]--;
if(in[e]==0) q.push(e);
}
}
}
原文参考:https://blog.youkuaiyun.com/tran_sient/article/details/96142610