确定比赛名次
题目描述
核心思路
题意:输出字典序最小的拓扑序列
主要思路:在当前步骤,在所有入度为0的点中输出编号最小的。
考虑用BFS实现拓扑排序:
修改BFS的拓扑排序程序,将普通队列修改成优先队列Q,在 Q Q Q中存放入度为0的节点,每次输出编号最小的节点,然后把它的后续节点的入度减1,入度减为0的再放进 Q Q Q中,这样就能输出一个字典序最小的拓扑序列了。
如下图:
考虑这题可以使用DFS输出字典序最小的拓扑序列嘛?其实是不行的。上面处理的过程相当于把点按优先级分成了不同的层次,在每个层次都要把这一层入度减为0的点按字典序从小到大输出;而DFS是深度搜索,处理的是上下层之间的关系,不能处理这种同层之间的关系。
代码
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<functional>
using namespace std;
const int N=510;
int n,m;
int g[N][N]; //邻接矩阵
int d[N];
int seq[N]; //存储字典序最小的拓扑序列
int cnt=1;
void topsort()
{
//优先队列
priority_queue<int,vector<int>,greater<int> > q;
for(int i=1;i<=n;i++)
{
if(!d[i])
q.push(i);
}
int cnt=1;
while(!q.empty())
{
int t=q.top();
q.pop();
seq[cnt++]=t; //将t存储拓扑序列中
for(int j=1;j<=n;j++)
{
if(g[t][j])
{
if(--d[j]==0)
q.push(j);
}
}
}
}
int main()
{
while(cin>>n>>m)
{
memset(g,0,sizeof g);
memset(d,0,sizeof d);
while(m--)
{
int a,b;
cin>>a>>b;
if(!g[a][b])//防止有重边
{
g[a][b]=1;
d[b]++;
}
}
topsort();
for(int i=1;i<n;i++)
printf("%d ",seq[i]);
printf("%d\n",seq[n]);
}
return 0;
}