https://vjudge.net/problem/UVA-10305(uva0305 点击打开链接)
思路:有向无环图才有拓扑排序。判断是有向无环图后,找入度为0的点,然后把这个点以及从该点到其他点的边去掉,重复寻找入度为0 的点存下来,存下来的点就是拓扑排序后的序列。
分析:可以用队列写,也可以用dfs写。队列复杂度高,易理解;dfs复杂度低,难理解(算法竞赛入门经典上用dfs写的,就照着dfs写的)。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;
const int maxn = 100 + 10;
int g[maxn][maxn];//点与点之间的边
int c[maxn];//记录是否被访问过,0 表示为访问过,-1 表示正在访问 1 表示已经访问过了
int topo[maxn];//存入度为0的点,就拓扑序列
int n,m,t;
bool dfs(int u)
{
c[u] = -1;
for(int i = 0;i < n;i++)
{
if(g[u][i])//如果u到i有边
{
if(c[i] < 0)//如果i点正在被访问,说明i和u是同一个点,是自环,无拓扑排序
return false;
if(!c[i] && !dfs(i))//如果i未被访问过,但是dfs不满足
return false;
}
}
c[u] = 1;//标记已被访问过
topo[--t] = u;//u是拓扑排序后的最后一个点
return true;
}
bool toposort()
{
t = n;
memset(c,0,sizeof(c));
for(int i = 0;i < n;i++)
{
if(!c[i])//如果i点没有访问过
{
if(!dfs(i))//就访问i点
{
return false;
}
}
}
return true;
}
int main()
{
while(scanf("%d%d",&n,&m),n)
{
memset(g,0,sizeof(g));
for(int i = 1;i <= m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
g[--u][--v] = 1;//先--,因为点是从0开始存的
}
toposort();
for(int i = 0;i < n;i++)
{
if(i != 0)
printf(" ");
printf("%d",topo[i] + 1);//点是从0开始存的,但是实际是从1开始
}
printf("\n");
}
}