http://acm.hdu.edu.cn/showproblem.php?pid=1285
因为输入数据一定有解,并且要编号小的队伍在前,那么用优先队列存储结果集即可。
//拓扑排序关键在于需要维护一个入度为0的顶点的集合。(只出不入)
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
#define Max 510
using namespace std;
struct ADJ
{
int v;
int last;
};
ADJ adj[Max*Max];
int cnt_edge;//边的数量
int node[Max]; //以x为起点的最后一条边的编号
int in[Max];//入度
int n,m;
priority_queue<int,vector<int>,greater<int> >q;//题目要求编号小的队伍在前,所以用优先队列,从小到大排序
void add_edge(int x,int y) //队列模拟集合
{
adj[cnt_edge].last=node[x];
adj[cnt_edge].v=y; //当前边的终点。
node[x]=cnt_edge; //以x为起点的最后一条边的编号
cnt_edge++;
}//邻接表的建立
void clear()
{
cnt_edge=0; //边的数量从0开始
memset(in,0,sizeof(in)); //初始化入度为0
memset(node,-1,sizeof(node)); //初始化每个点编号为-1
while(!q.empty()) q.pop();
}
void top_sort()
{
vector<int>vec; //保存结果集
int now,next,j;
while(!q.empty())
{
now=q.top();
vec.push_back(now); //从集合中取出一个点,将该顶点放入结果集当中,
q.pop();
for(j=node[now];j!=-1;j=adj[j].last)//遍历邻接表,从当前顶点遍历与之相连的所有边
{
next=adj[j].v;
in[next]--; //入度减1,表示移除这条边
if(in[next]==0) q.push(next); //如果该顶点的入度在减去这条边之后为0,那么将这个顶点也放入结果集当中
}
}
for(j=0;j<vec.size();j++)
{ //输出结果集
if(j==0) printf("%d",vec[j]);
else printf(" %d",vec[j]);
}
printf("\n");
}
int main()
{
//freopen("b.txt","r",stdin);
while(scanf("%d %d",&n,&m)==2)
{
clear();
int x,y;
while(m--)
{
scanf("%d %d",&x,&y);
add_edge(x,y);
in[y]++; //x指向y的边,y的入度加1
}
int i;
for(i=1;i<=n;i++)
if(in[i]==0) //把入度为0的点加入集合
q.push(i);
top_sort();
}
return 0;
}