HDU1285 确定比赛名次 拓扑排序模板题

继续填坑。。。
题意:好多队伍比赛,给你很多数对(a,b)表示a的排名在b之前。问你一种可能的排名方式,且编号小的在前面。(这句话就不得不用基于堆实现的优先队列)
思路:排名靠前的,说明该队伍前面队伍少,即该队伍所表示的点入度小
根据入度不同,我们把它们化为多个不同的梯队。如入度为0,是第一梯队,表示之前没有队伍比他们厉害,有夺冠的潜质。所以刚开始先把入度为0的入优先队列(为什么?因为要求最小的编号在前面)。
然后每次拿优先队列第一个点来减少以该点作为起点的 终点的入度。即当你用完队首的这个点,那这个点就可以弹出了,对于弹出的这个点,它所连的所有终点岂不是入度都可以减一嘛,这样那些终点甚至就有和早它一个梯队的点有了争先的权利(只要它编号够小就能上位)。
然后因为是优先队列,所以拿完队列的首元素,就可以直接入q2 来记录答案了~
最后输出答案的时候记得弹出最后一个元素,因为是多组输入,会影响下一组。
下面是AC代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m; 
int map[502][502];//存地图 
int in[502];//入度
priority_queue<int,vector<int>,greater<int> > q;//插入后自动排序  从小到大 
queue<int> q2;//一般队列存结果!!!
int topo(){//把答案存入q2 
	for(int i=1;i<=n;i++){
		if(in[i]==0){
			q.push(i);//先把所有入度为0的入优先队列 
		}
	}
	while(!q.empty()){//对优先队列进行操作 
		int head=q.top();
		q2.push(head);//把头头放入一般队列
		q.pop();//把头头弹出去
		for(int j=1;j<=n;j++){//寻找地图上从head这个点开始的 
			if(map[head][j]){//只要地图上有这条边 
				in[j]--;	//因为该边的起点已经gg  所以终点入度-- 
				if(in[j]==0){//若入度为0  则可以当头头~  所以可以入优先队列 
					q.push(j);	//切记这个判断要在有这条边的基础上(有这条边才能保证终点原来入度不为0!!! 
				}				//WA了!!! 
			}
		}
	}
	return 0;
}
int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		memset(map,0,sizeof(map));
		memset(in,0,sizeof(in)); 
		int a,b;
		while(m--){
			scanf("%d%d",&a,&b);
			if(map[a][b]==0){//这波操作防重边 
				map[a][b]=1;
				in[b]++;
			}
		}
		topo();//功能:把结果存入一般队列queue  q2
		//下面输出结果 
		while(q2.size()>1){
			printf("%d ",q2.front());
			q2.pop();
		}
		printf("%d\n",q2.front());
		q2.pop();//最后记得pop掉这个  让q2变空 !!!注意是多组输入  会影响下一组!!! 
	}
	return 0;
}

你可能感兴趣的:(拓扑排序,拓扑排序)