原题:点击右边的-->原题
题意:给你一个n,表示有n个任务 ,给你m组两个数,表示两个任务的先后顺序,让你对这个n个任务排序。
思路:一个裸的拓扑排序。
拓扑排序:把一个图的所有结点排序,使得每个有向边(u,v)对应的u都在v的前边。
用法:可以用DFS求出所有有向无环图(DAG)的拓扑排序。如果排序失败,说明有向图存在有向环,不是DAG
实现思路:对每一条边进行一次dfs,看看这个u是否有前置的点,找到一个没有后置的点的点放进topo数组里。然后标记这个点表示已经使用过。代码中数组c的作用是标记,分别有三种情况分别为-1,0,1。分别表示正在访问这个点,尚未访问过,已经使用过。
代码如下
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Maxn = 1000;
int G[Maxn][Maxn],c[Maxn],topo[Maxn];
int n,m,t;
bool dfs(int u){
c[u] = -1; // 表示正在访问中
for(int v = 0 ; v < n ; v++){
if(G[u][v]){
if(c[v] < 0) return false ; //如果出现c【v】=-1 代表v是正在访问中的内容,说明出现了环
else if(!c[v] && !dfs(v)) return false ; // 一直往下递归 看看有没有换,如果没有环的话,递归出的应该是最后一个
}
}
c[u] = 1; //访问结束
topo[--t] = u; // topo数组储存任务
return true;
}
bool toposort(){
t = n;
memset(c,0,sizeof(c));
for(int i = 0 ;i < n ;i ++){
if(!c[i])
if(!dfs(i)) return false ;
}
return true;
}
int main(){
while(scanf("%d%d",&n,&m)){
if(n == 0) break;
memset(G,0,sizeof(G));
for(int i = 0 ; i < m ; i++){
int a,b;
scanf("%d%d",&a,&b);
a--;
b--;
G[a][b] = 1;
}
if(toposort()){
for(int i = 0 ;i < n - 1 ; i++)
printf("%d ",topo[i]+1);
printf("%d",topo[n-1]+1);
}
else printf("No\n");
}
return 0;
}