//拓扑排序关键在于一个入度,首先说明入度的作用,这就好比学科A,入度就是到这门学科的边的条数,如果到这门学科为0了,就说明不需要先学什么
//那么自然就要学习这门学科,然后再将与这门学科相连的其他学科的入度减一,因为他们原来入度(即边的条数包含A学科到自己的边,现在A学科学过了,自然少了一个障碍,
//而如果此时正好该门学科入度变成0了,那么又可以学习该门学科~~
//入度的求法:从上文可以看出入度就是到该点的边的条数,那么只需要在读入时边读,边让终点的入度加一即可~~(因为是有向图嘛)
//这里还需注意如果是含有回路,那么就会出错,因为你不可能先学高数,再学离散数学,(高数->离散)结果发现离散还要以高数为基础(离散->高数)...
//那么自然就要学习这门学科,然后再将与这门学科相连的其他学科的入度减一,因为他们原来入度(即边的条数包含A学科到自己的边,现在A学科学过了,自然少了一个障碍,
//而如果此时正好该门学科入度变成0了,那么又可以学习该门学科~~
//入度的求法:从上文可以看出入度就是到该点的边的条数,那么只需要在读入时边读,边让终点的入度加一即可~~(因为是有向图嘛)
//这里还需注意如果是含有回路,那么就会出错,因为你不可能先学高数,再学离散数学,(高数->离散)结果发现离散还要以高数为基础(离散->高数)...
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
queue<int>q;
int main()
{
int n,m,c,d,count,i,j;
int a[101][101];
int ans[101];
int indegree[101];
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
indegree[i]=0;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
a[i][j]=0;
for (i=1;i<=m;i++)
{
scanf("%d%d",&c,&d);
a[c][d]=1;
indegree[d]++;//到d的点边又多了一条(即入度加一)
}
count=0;
for (i=1;i<n;i++)
if (!indegree[i])
{
q.push(i);//找寻入度为0的点
ans[++count]=i;
}//先将所有入度为0的点入栈,同时记录下节点
while(!q.empty())
{
int temp=q.front();
q.pop();
for (i=1;i<=n;i++)
if (a[temp][i])//和i边相连
{
indegree[i]--;//i边入度减一
if (!indegree[i])//如果减过之后发现i边的入度减少为0,那么就将其入栈
{
q.push(i);
ans[++count]=i;//保存路径
}
}
}
if (count<n) printf("含有回路\n");//为什么count<n时就含有回路,比如三角形1->2,2->3,3->1那么可以看出每一个点的入度都是1,也就是外面的图形永远无法访问到首位相连的里面的图形,所以ocunt一定会小于n.
else
for (i=1;i<=n;i++)//否则输出保存的路径
printf("%d ",ans[i]);
printf("\n");
return 0;
}
例如下面两图