题意:
一共n只猫猫,编号依次为1至n。有m场猫猫比赛,p1 p2表示猫猫p1赢了猫猫p2。现求字典序最小的名次序列。
思路:
猫猫之间的胜负关系可以构成一张有向无环图,p1赢了p2等价于有向边(p1,p2),在最终的名次序列里p1要在p2的前面。
用toposort来求拓扑序列:计算所有顶点的入度,当入度为0时将顶点加入到小根堆。当小根堆不为空时,取出一个顶点u,将其加入到答案序列中,然后对所有的(u,v),将顶点v入度-1,若v入度为0,加入小根堆。最后输出就行,应注意输出格式,最后一名后没有空格。
总结:
一道求拓扑序列的题目,因为要求字典序最小的名次序列,将toposort中的队列变为了小根堆。
代码:
#include <iostream>
#include <queue>
using namespace std;
int n,m;
int indeg[510]; //入度
//链式前向星
struct edge
{
int to,next,w;
};
edge e[250000];
int head[510],tot;
void add(int x,int y,int w)
{
e[++tot].to=y,e[tot].next=head[x];
e[tot].w=w,head[x]=tot;
}
void toposort()
{
priority_queue<int,vector<int>,greater<int> >q;
for(int i=1;i<=n;i++)
if(indeg[i]==0) q.push(i);
vector<int> ans;
while(!q.empty())
{
int u=q.top();
q.pop();
ans.push_back(u);
for(int i=head[u];i!=0;i=e[i].next)
{
int v=e[i].to;
indeg[v]--;
if(indeg[v]==0) q.push(v);
}
}
//输出
for(int i=0;i<ans.size()-1;i++)
cout<<ans[i]<<" ";
cout<<ans[ans.size()-1]<<endl;
}
int main()
{
while(cin>>n>>m)
{
//初始化
for(int i=0;i<=n;i++)
head[i]=0,indeg[i]=0;
tot=0;
//读入
for(int i=0;i<m;i++)
{
int p1,p2;
cin>>p1>>p2;
add(p1,p2,1);
indeg[p2]++;
}
toposort();
}
}