HDU-4857 逃生(逆向拓扑排序)

Posted jiamian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU-4857 逃生(逆向拓扑排序)相关的知识,希望对你有一定的参考价值。

 

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

 

 

这是一种比较坑的排序,要求编号小的尽量排在前面,这里平时的是不一样的。

 

例子来自:https://blog.csdn.net/qq_41713256/article/details/80805338

技术图片

如果你用优先队列拓扑排序得到的是:3 5 6 4 1 7 8 9 2 0

但是正确答案为 6 4 1 3 9 2 5 7 8 0 这样使得小的(1)尽量在前面。

 

这题相当于逆向的拓扑排序,因为小的要尽量放前面。

如果正向拓扑的话,优先队列要设置成小的值优先,这样万一出现一个比较小的入度为0的点,就会直接放进queue去 ,这样万一后面还有更小的点的话就出错了。

所以要逆向拓扑,从右往左想,所有特殊条件都没有指明谁要在它后面的点先放(即这个点的出度为0),优先队列设置成大的优先。

 


思路:逆向拓扑 + 优先队列

1.反向建边,点大的优先级高。
2.用拓扑排序+优先队列,逆向输出序列即可。

 

 

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <string>
 5 #include <math.h>
 6 #include <algorithm>
 7 #include <vector>
 8 #include <stack>
 9 #include <queue>
10 #include <set>
11 #include <map>
12 #include <sstream>
13 const int INF=0x3f3f3f3f;
14 typedef long long LL;
15 const double eps =1e-8;
16 const int mod=1e9+7;
17 const int maxn=1e5+10;
18 using namespace std;
19 
20 struct edge
21 {
22     int to;
23     int next;
24 }E[maxn];
25 int head[maxn];
26 int tot;
27 void add(int u,int v)
28 {
29     E[tot].to=v;
30     E[tot].next=head[u];
31     head[u]=tot++;
32 } 
33 
34 priority_queue<int> qe;
35 vector<int> ans;
36 int in[maxn];
37 
38 void init()
39 {
40     tot=0;
41     memset(in,0,sizeof(in));
42     memset(head,-1,sizeof(head));
43     while(!qe.empty()) qe.pop();
44     ans.clear();
45 }
46 
47 int main()
48 {
49     #ifdef DEBUG
50     freopen("sample.txt","r",stdin);
51     #endif
52     
53     int T;
54     scanf("%d",&T);
55     while(T--)
56     {
57         int n,m;
58         scanf("%d %d",&n,&m);
59         init();
60         for(int i=1;i<=m;i++)
61         {
62             int u,v;
63             scanf("%d %d",&u,&v);
64             add(v,u);
65             in[u]++;
66         }
67         for(int i=1;i<=n;i++)
68             if(in[i]==0) qe.push(i);
69         while(!qe.empty())
70         {
71             int u=qe.top(); qe.pop();
72             ans.push_back(u);
73             for(int i=head[u];i!=-1;i=E[i].next)
74             {
75                 int v=E[i].to;
76                 in[v]--;
77                 if(in[v]==0) qe.push(v);
78             }
79         }
80         for(int i=ans.size()-1;i>=0;i--)
81             printf(i==0?"%d
":"%d ",ans[i]);
82     } 
83         
84     return 0;
85 }

 

 

 

-

以上是关于HDU-4857 逃生(逆向拓扑排序)的主要内容,如果未能解决你的问题,请参考以下文章

HDU-4857 逃生(逆向拓扑排序)

HDU 4857 逃生(拓扑排序逆向+邻接表存图)

HDU-4857-逃生-反向拓扑排序+优先队列

逃生(HDU4857 + 反向拓扑排序)

HDU 4857 逃生 (反向拓扑排序 & 容器实现)

hdu4857 逃生反向建图+拓扑排序