本题难点:
1.确定排名.
2.图中有重边
3.符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
解决方案:
1.对于确定排名问题,每个队伍的入度就是失败的次数,出度就是胜利次数。排名越靠前,显然队伍的入度数越少。通过入度数来决定排序的方法就是拓扑排序。
2.用邻接矩阵。邻接表需要判重边不便于运算。
3.拓扑排序的入度为0的缓冲队列的取点方案是取队列中的最小值。可以用优先级队列实现。
拓扑排序算法有很多,这里采用削入度的方法。如果入度为0,则入队;否则削入度和对应边,直到入度为0才入队。
这个过程就像你学习某门课程,老师告诉你学习这门课的基础课是哪些,你必须学完这些基础课,才能听懂这门课。实际课程有两种情况:不需要学基础课,需要学基础课。对应入度为0、入度不为0的情况。你想掌握这门需要学基础课的课程,就必须先学习基础课程,这个过程就是削入度的过程。
#include<bits/stdc++.h>
using namespace std;
const int N=510,M=N*N;
int maze[N][N],d[N],idx;
int que[N];
priority_queue<int,vector<int>,greater<int> > heap;//编号小的队优先
void add(int u,int v){
if(maze[u][v]==1)return;
maze[u][v]=1;
d[v]++;//入度增加了
}
int main(){
int n,m,u,v;
freopen("test.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
idx=0;
memset(maze,0,sizeof(maze));//初始化图与入度
memset(d,0,sizeof(d));
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
}
for(int i=1;i<=n;i++)
if(d[i]==0){
heap.push(i);
}
while(!heap.empty())
{
int t=heap.top();
heap.pop();
que[++idx]=t;
for(int i=1;i<=n;i++)//顶点有效范围[1,n]
{
if(maze[t][i]){
maze[t][i]=0;//消边
d[i]--;//消入度
if(d[i]==0)heap.push(i);
}
}
}
for(int i=1;i<idx;i++)
cout<<que[i]<<' ';
cout<<que[idx]<<endl;
}
return 0;
}