【HDOJ】4587 逃生 反向建图+拓扑排序+逆序输出
作者:互联网
题目链接
http://192.168.102.19/showproblem.php?pid=4857
题意
n个人要逃生,给你一些条件(形如a b,意为a必须在b之前逃生),满足限制条件时还要满足让1号最先逃生,其次是2号,3号.....输出满足题意的逃生顺序
注意
题意的理解很重要。
在拓扑排序中常见的是让答案的字典序最大/最小;然而这道题的意思是让1号最先,其次是2号....
例如,给出4->1,3->2两条限制关系,为了让1最先,答案最终会是4 1 3 2(而不是3 2 4 1)
正解
这道题中我们既要考虑到让现存的编号最小的点先输出,又要保证输出它之前前面的点顺序也是满足拓扑序的
于是可以反向建图,利用优先队列(大根堆)做拓扑排序,再逆序输出即为答案
code
这题还要注意会有重复的边,所以我用了set存边的关系
细节见代码
#include<bits/stdc++.h> //逃生
using namespace std;
const int N = 30005;
int t,n,m;
int rd[N];
set<int>st[N];
vector<int>ans;
priority_queue<int,vector<int>,greater<int>>q;
void topo(){
while(!q.empty()){
int now=q.top();
q.pop();
ans.push_back(now);
for(auto i=st[now].begin();i!=st[now].end();i++){
rd[*i]--;
if(rd[*i]==0){
q.push(*i);
}
}
}
}
int main(){
// cin>>t;
// while(t--){
while(cin>>n>>m){
ans.clear();
for(int i=1;i<=n;i++){
st[i].clear();
rd[i]=0;
}
for(int i=1,x,y;i<=m;i++){
scanf("%d%d",&x,&y);
if(st[x].count(y)==0){
st[x].insert(y);
rd[y]++;
}
}
for(int i=1;i<=n;i++){
if(!rd[i]){
q.push(i);
}
}
topo();
for(int i=0;i<ans.size();i++){
if(i==0) printf("%d",ans[i]);
else printf(" %d",ans[i]);
}
puts("");
}
return 0;
}
标签:题意,int,拓扑,rd,建图,逃生,4587,now,逆序 来源: https://www.cnblogs.com/re0acm/p/15972443.html