拓扑排序
先统计所有节点的入度,对于入度为0的节点就可以分离出来,然后把这个节点指向的节点的入度减一。
一直做这个操作,直到所有的节点都被分离出来。先统计所有节点的入度,对于入度为0的节点就可以分离出来,然后把这个节点指向的节点的入度减一
时间复杂度 O ( V + E ) O(V+E) O(V+E)
点数 + 边数
参考文献
https://blog.csdn.net/qq_41713256/article/details/80805338
例题1:ZCMU-2153 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
原题链接:
http://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=2153
C++ 代码
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <iostream>
#include <algorithm>
#define ios ios::sync_with_stdio(false), cin.tie(0)
#define sd(n) scanf("%d", &n)
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define fs first
#define se second
#define debug(x) cout << #x << ": " << x << endl
#define MOD 1000000007
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int N = 1e6 + 10;
int in[50];
vector<int> ans , edge[50];
int main()
{
char a,b,x;
set<int> k;
priority_queue< int, vector<int>, greater<int> >q;
while(~scanf(" %c%c%c ", &a,&x,&b))
{
k.insert(a - 'A'), k.insert(b- 'A');
if(x == '>')
{
in[b - 'A'] ++;
edge[a - 'A'].push_back(b - 'A');
}
else
{
in[a - 'A'];
edge[b - 'A'].push_back(a - 'A');
}
}
rep(i , 0 , 29)
if(in[i] == 0 && k.count(i) != 0) //将入度0的点 入队
q.push(i);
while(!q.empty())
{
int p = q.top(); q.pop(); //选入度为0的点,出队
ans.push_back(p);
for(int i=0;i<edge[p].size();i++)
{
int y = edge[p][i];
in[y] --;
if(in[y] == 0 && k.count(y) != 0) //将入度0的点 入队
q.push(y);
}
}
if(ans.size() == k.size())
for(int i=0;i<ans.size();i++)
cout << char(ans[i] + 'A');
else cout << "No Answer!" << endl;
return 0;
}
例题2
2022年兰州理工大学天梯赛校内选拔赛题目7-14 羽毛球比赛 (30 分)
宇航员训练基地要举行羽毛球赛,共有N名队员参加比赛,他们的编号分别为1,2,3,……,N,宇航员王明是比赛的总裁判,但是由于电脑故障,比赛排名没有了,幸运的是王明保留有各场比赛的输赢情况,其中,(Pi****,Pj)表示Pi队员赢了Pj****队员,现在请你帮王明计算出羽毛球赛的排名。由于排名情况不唯一,编号小的队员排名在前。
输入格式:
第一行输入两个整数N和M,其中N(1≤N≤500)表示参加比赛的人数,M表示举行比赛的场次。
以下M行,每行有两个整数Pi和Pj,表示Pi赢了Pj。
输出格式:
输出比赛排名,排名之间有空格分隔。
注意:输入数据保证一定有符合要求的排名。
输入样例:
在这里给出一组输入。例如:
4 3
1 4
4 3
2 3
输出样例:
在这里给出相应的输出。例如:
1 2 4 3
C++代码
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <map>
#include <set>
#include <cmath>
#include <iostream>
#include <algorithm>
#define ios ios::sync_with_stdio(false), cin.tie(0)
#define sd(n) scanf("%d",&n)
#define rep(i,a,n) for(int i = a; i <= n ; i++)
#define per(i,a,n) for(int i = n; i>= a; i--)
#define fs first
#define se second
#define debug(x) cout << #x << ": " << x << endl
#define MOD 1000000007
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int N = 5e2 + 10;
int n ,m;
int in[N]; //入度
priority_queue<int, vector<int>, greater<int>> q;
vector<int> edge[N]; //边
vector<int> ans; //拓扑序列
int main()
{
ios;
cin >> n >> m;
while(m -- )
{
int a, b;
cin >> a >> b;
in[b]++;
edge[a].push_back(b);
}
rep(i, 1, N)
if(in[i] == 0) //将入度0的点 入队
q.push(i);
while(!q.empty())
{
int p = q.top(); q.pop(); //选入度为0的点,出队
ans.push_back(p);
for(int i = 0; i < edge[p].size(); i++)
{
int y = edge[p][i];
in[y]--;
if(in[y] == 0)
q.push(y);
}
}
bool temp = false;
// if(ans.size() == n)
rep(i , 0 , n-1)
{
if(temp) cout << " ";
cout << ans[i];
temp = true;
}
return 0;
}