-
- HDU - 4857
-
- 【题意】
- 有n个人,m个优先级a,b
- 表示a优先于b,并且每个人有个编号的优先级,输出顺序。
- 【分析】
- 编号最小的节点要尽量排在前面;在满足上一个条件的基础上,编号第二小的节点要尽量排在前面;在满足前两个条件的基础上,编号第三小的节点要尽量排在前面……依此类推。(注意,这和字典序是两回事,不可以混淆。)
- 不是字典序,自然不能每次优先队列优先最小编号出队。
-
- 这里有个例子,有三条互相平行的路径:6 → 4 → 1、 3 → 9 → 2 和 5 → 7 → 8。一条路径上的各个节点的先后关系都是不能改变的。
- 如果直接优先队列优先最小值的话去求的结果会是:3 5 6 4 1 7 8 9 2 0
- 是不符合题意要求的,因为明显可以使1号点排在更前边。
- 正确的顺序应该是6 4 1 3 9 2 5 7 8 0
- 那么我们如何去求这个结果呢,使用反向拓扑 + 优先队列(优先最大值)
- 这样想,我们每次优先最小的并不能保证按上述的顺序排列,但是,我们优先最大值,把编号大的点给他分配一个尽量大的一个编号,这肯定是符合要求的,最后倒序输出即可。
#include<bits/stdc++.h>
using namespace std;
#define maxn 300005
int in[maxn],t,n,m,u,v,ans[maxn],cnt;
vector<int>mmp[maxn];
void topo()
{
priority_queue<int,vector<int> >q;
for(int i=1; i<=n; i++)
if(!in[i])
q.push(i);
while(!q.empty())
{
int now=q.top();
q.pop();
for(int i=0; i<mmp[now].size(); i++)
{
in[mmp[now][i]]--;
if(!in[mmp[now][i]])
q.push(mmp[now][i]);
}
ans[cnt++]=now;
}
for(int i=n-1; i>0; i--)
cout<<ans[i]<<" ";
cout<<ans[0]<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
for(int i=1; i<=n; i++)
mmp[i].clear();
cnt=0;
memset(in,0,sizeof(in));
memset(ans,0,sizeof(ans));
cin>>n>>m;
while(m--)
{
cin>>u>>v;
in[u]++;
mmp[v].push_back(u);
}
topo();
}
return 0;
}