拓扑排序-Kahn算法
该算法的关键在于需要维护一个入度为0的顶点的集合:
每次从该集合中取出(如果要求输出时编号小的在前,可以用优先队列保存集合)一个顶点,将该顶点放入保存结果的List中。
紧接着循环遍历由该顶点引出的所有边,从图中移除这条边,同时获取该边的另外一个顶点,如果该顶点的入度在减去本条边之后为0,那么也将这个顶点放到入度为0的集合中。然后继续从集合中取出一个顶点…………
当集合为空之后,检查图中是否还存在任何边,如果存在的话,说明图中至少存在一条环路。不存在的话则返回结果List,此List中的顺序就是对图进行拓扑排序的结果。
题目链接:确定比赛名次(HDU – 1285 )
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#define INF 1<<29
using namespace std;
int in[510],n,m;
bool vis[510];
vector<int> vec[510];
void bfs()
{
//优先队列存储,保证输出时编号小的靠前
priority_queue<int,vector<int>,greater<int> > q;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(!in[i])//首先将入度为0的点入队(即没有前驱的顶点)
{
q.push(i);
vis[i]=1;
}
}
int flag=0;
while(!q.empty())
{
int top=q.top(); q.pop();//取出top
if(flag)
printf(" ");//输出
printf("%d",top);
flag=1;
for(int i=0;i<vec[top].size();i++)
{
int now=vec[top][i];
in[now]--;//将top的所有直接后继顶点入度-1
if(!vis[now] && !in[now])//如果这个顶点的入度为0,将它入队
{
vis[now]=1;
q.push(now);
}
}
}
printf("\n");
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int u,v;
memset(in,0,sizeof(in));
for(int i=1;i<=n;i++)
vec[i].clear();
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
vec[u].push_back(v);
in[v]++;//v的入度加一
}
bfs();
}
return 0;
}