其他分享
首页 > 其他分享> > 【HDOJ】4587 逃生 反向建图+拓扑排序+逆序输出

【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