拓扑序
约 309 个字 127 行代码 预计阅读时间 3 分钟
在判断无向图中是否存在环时,是将所有 度 <= 1 的结点入队;
在判断有向图中是否存在环时,是将所有 入度 = 0 的结点入队。
多种方案,让1尽量靠前,1最靠前的方案里,选择2尽量靠前的方案,满足前两条件的方案里,选择3尽量靠前的方案....
这个限制不是字典序最小,比如下例,解决方法是反向建图,序号大的先出队,答案按照出队逆序输出
input
3 1
3 1
wrong output
2 3 1
true output
3 1 2
题目¶
有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 500+5;
const int maxm = maxn * maxn;
// 建图
struct node{
int to, next;
}edge[maxm];
int head[maxn], cnt;
void add(int u, int v){
edge[++cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
int du[maxn]; // 入度
int n, m;
queue<int> ans; // 获取答案
int topu1(void){
queue<int> q; // 入度为0的点
for(int i = 1;i <= n;i++){
if(du[i] == 0) q.push(i);
}
int tot = 0;
while(!q.empty()){
int now = q.front();
q.pop();
ans.push(now);
tot++;
for(int i = head[now];i;i = edge[i].next){ // 遍历这个点所连向的边,把这条边删掉
int to = edge[i].to;
du[to]--; // 入度减一
if(du[to] == 0) q.push(to);
}
}
// 拓扑排序判断是否有环
if(tot == n) return 1; // 无环
else return 0; // 有环
}
int topu2(void){
priority_queue<int, vector<int>, greater<int> > q;
for(int i = 1;i <= n;i++){
if(du[i] == 0) q.push(i);
}
int tot = 0;
while(!q.empty()){
int now = q.top(); // 寻找入度的点里面,值最小的点
q.pop();
ans.push(now);
tot++;
for(int i = head[now];i;i = edge[i].next){
int to = edge[i].to;
du[to]--;
if(du[to] == 0) q.push(to);
}
}
if(tot == n) return 1;
else return 0;
}
int main(void){
while(scanf("%d %d", &n, &m) != EOF){
memset(du, 0, sizeof(du));
memset(head, 0, sizeof(head));
cnt = 0;
for(int i = 0; i < m;i++){
int u, v;
scanf("%d %d", &u, &v);
add(u, v);
du[v]++; // v的入度增加
}
topu2();
int flag = 0;
while(!ans.empty()){
int now = ans.front();
ans.pop();
if(flag) putchar(' ');
flag = 1;
printf("%d", now);
}
puts("");
}
return 0;
}
板子¶
namespace topuSort
{
queue<int> q;
int in[N];
vector<int> e[N];
int n;
void init(int nn)
{
n=nn;
memset(in,0,sizeof(int)*(n+1));
for(int i=1;i<=n;++i)
e[i].clear();
while(!q.empty())
q.pop();
}
void addEdge(int u,int v)
{
e[u].push_back(v);
++in[v];
}
bool run()
{
for(int i=1;i<=n;++i)
{
if(!in[i])
q.push(i);
}
int u,cnt=0;
while(!q.empty())
{
u=q.front();
q.pop();
++cnt;
for(int v:e[u])
{
if(--in[v]==0)
q.push(v);
}
}
return cnt==n;
}
};