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