博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 4857 逃生 (反向拓扑排序 & 容器实现)
阅读量:4676 次
发布时间:2019-06-09

本文共 2474 字,大约阅读时间需要 8 分钟。

题目链接:

逃生

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 4505    Accepted Submission(s): 1282

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
 
题意:n个结点,m个拓扑关系(a,b)表示a必须排在b前面,在满足m个拓扑关系关系的前提下使得小的结点尽可能的排在前面。
也就是说我们现在要从1号结点开始考虑,如果要排1号结点,根据拓扑关系,首先必须排哪些结点,如果排好了1号结点,则继续考虑2号结点 ,3号结点。。 
我们先看两个例子: 
存在拓扑关系: 
5 -> 3 -> 1 
6 -> 4 -> 2 
直接拓扑排序的结果是 5 3 1 6 4 2,结果是正确的(1号尽可能的在前面了) ,看起来好像直接拓扑排序就可以了,
但是为什么提交后却wa了呢,别急,我们再看一个例子: 
6 -> 3 -> 1 
5 -> 4 -> 2 
直接拓扑排序的结果是:5 4 2 6 3 1 ,结果是错误的,因为我们可以把1号安排到更前面的位置 即:6 3 1 5 4 2(正确答案)。 
看到这里应该就知道为什么直接拓扑排序不行了吧,我们分析一下为什么会出现这样的状况,对于多条弧或者边,
我们是先删除弧尾结点比较小的结点即(5号结点比6号结点小,先删除以该点为尾的弧),而这也正是问题所在,
我们希望的是优先删除弧头比较小的弧的(1号结点比2号结点小,因优先删除以1号为头的弧)。 
好了,问题找到了,现在我们在来想如何解决问题,我们可以尝试一下逆向思维,即我们先考虑哪些点应该靠后释放,
这样的话我们就可以把拓扑关系反过来(即弧头和弧尾调换),然后做拓扑排序,
然后我们可以根据原来的弧头(现在变成弧尾)的大小来释放结点,由于现在的问题变成哪些最后释放,
那么就应该优先考虑弧尾(原来的弧头)比较大的,可以通过优先队列来解决。
 
1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 using namespace std; 8 #define maxx 30010 9 vector
vec[maxx];10 priority_queue
q; //优先队列11 int num[maxx],in[maxx];12 int main ()13 {14 int t,u,v,m,n,i,j;15 scanf("%d",&t);16 while (t --)17 {18 scanf("%d%d",&n,&m);19 for (i = 1; i <= n; i ++) //清空容器内的数据20 vec[i].clear();21 memset(in,0,sizeof(in)); //入度初始化为022 23 for (i = 0; i < m; i ++)24 {25 scanf("%d%d",&u,&v);26 in[u] ++;27 vec[v].push_back(u);28 }29 for (i = 1; i <= n; i ++) //将入度为0的点加入优先队列30 if (in[i]==0) q.push(i);31 32 j = 0;33 while(!q.empty())34 {35 int k = q.top();36 q.pop();37 num[j ++] = k;38 int len = vec[k].size();39 for (i = 0; i < len; i ++) // 删除与度数为0的节点相关联的边40 {41 int l = vec[k][i];42 in[l] --;43 if (in[l]==0)44 q.push(l);45 }46 }47 for (i = j-1; i >= 0; i --)48 {49 if (i==0)50 printf("%d",num[i]);51 else52 printf("%d ",num[i]);53 }54 printf("\n");55 }56 return 0;57 }

 

转载于:https://www.cnblogs.com/yoke/p/6080304.html

你可能感兴趣的文章
filter 过滤器(监听)
查看>>
CSS 布局整理(************************************************)
查看>>
谈谈一些有趣的CSS题目(三)-- 层叠顺序与堆栈上下文知多少
查看>>
ROI区域图像叠加&初级图像混合 综合实例
查看>>
Declare Cusror of SQLServer
查看>>
Linux进程间通信---共享内存
查看>>
正则表达式二
查看>>
javascrip t函数中执行C#代码中的函数
查看>>
git gitk命令
查看>>
[Java] Java反射
查看>>
Computer Information
查看>>
交换机/路由器上的 S口 F口 E口
查看>>
P1298(矩阵切割)DP
查看>>
wzplayer for delphi demo截图
查看>>
团队第二周:SRS文档
查看>>
Zookeeper的安装与使用:
查看>>
密码策略限制最大与最小长度
查看>>
正则表达式模式
查看>>
使用iframe实现同域跨站提交数据
查看>>
Mouse点击之后,复制GridView控件的数据行
查看>>