逃生
Problem Description
糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。
现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。
同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。
负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。
那么你就要安排大家的顺序。我们保证一定有解。
Input
第一行一个整数T(1 <= T <= 5),表示测试数据的个数。
然后对于每个测试数据,第一行有两个整数n(1 <= n <= 30000)和m(1 <= m <= 100000),分别表示人数和约束的个数。
然后m行,每行两个整数a和b,表示有一个约束a号必须在b号之前。a和b必然不同。
Output
对每个测试数据,输出一行排队的顺序,用空格隔开。
Sample Input
1
5 10
3 5
1 4
2 5
1 2
3 4
1 4
2 3
1 5
3 5
1 2
Sample Output
1 2 3 4 5
这道题刚开始理解错题意了,这道题不是保证字典序,而是要最小的数字尽量在前面。
比如要1在不矛盾的情况下尽量在前面,然后2尽量在前面......
我刚开始:
要最小的尽量在前面,那就用priority_queue,然后从小到大,拓扑排序
但是这样只能保证拿出来的数字在当前队列中是最小的,而不能保证最后最小的一定在尽量前的位置。
比如:
较小,较大,最小,然后较大有连接最小的边,这样我输出是:较小,较大,最小,
但更优的情况是:较大,最小,较小
因为这样最小在更前的位置了。
那怎么做呢?
我是看了题解才知道的:
优先级:大到小的priority_queue
逆向建图+反向输出结果
为什么呢?
要最小的尽量前,我们就把最小的尽量放在后面,则priority_queue的优先级:从大到小,然后反向输出,
但是反向输出后的序列又要满足拓扑排序的规律,所以我们先要逆向建图。
这样反向输出后不就相当于正向了吗?
通过这道题自己也是学习了好多。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 #include<vector> 6 7 using namespace std; 8 9 const int maxn=30000+5; 10 11 int f[maxn]; 12 int inde[maxn]; 13 vector<int>edge[maxn]; 14 int tot; 15 16 void solve(int n) 17 { 18 tot=1; 19 20 priority_queue<int>que; 21 while(!que.empty()) 22 que.pop(); 23 24 for(int i=1;i<=n;i++) 25 { 26 if(inde[i]==0) 27 que.push(i); 28 } 29 30 while(!que.empty()) 31 { 32 int u=que.top(); 33 f[tot++]=u; 34 que.pop(); 35 36 for(int i=0;i<edge[u].size();i++) 37 { 38 int v=edge[u][i]; 39 inde[v]--; 40 if(inde[v]==0) 41 que.push(v); 42 } 43 } 44 45 for(int i=tot-1;i>1;i--) 46 printf("%d ",f[i]); 47 printf("%d\n",f[1]); 48 49 return ; 50 } 51 52 int main() 53 { 54 int test; 55 scanf("%d",&test); 56 57 while(test--) 58 { 59 int n,m; 60 scanf("%d%d",&n,&m); 61 62 memset(inde,0,sizeof(inde)); 63 for(int i=1;i<=n;i++) 64 edge[i].clear(); 65 66 int u,v; 67 for(int i=1;i<=m;i++) 68 { 69 scanf("%d%d",&u,&v); 70 edge[v].push_back(u); 71 inde[u]++; 72 } 73 74 solve(n); 75 } 76 77 return 0; 78 }
343ms