【vj】给定一些先后约束,求原序列(拓扑排序)
2016-01-21 20:39
369 查看
糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。
现在有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
http://vj.hsacm.com/contest/view.action?cid=67#problem/A
其实我觉得蛮有难度的,深搜,链表都试过了,都是写到结尾被否决掉。归根结底是我思路不行。
说说我一开始的思路:先把先后的链构出来,然后发现会有很多这样平行不相关的链,不知道怎么交叉输出。然后想到用拓扑思想逐个变成符合条件输出,但是可能会出现前面遍历过的点因为后面的点删掉而变符合,然后又可以删。然而是继续往下遍历还是找到前面的点深层遍历我没搞清楚(其实这里有个因果关系)。然后我又想到用深搜解决这个问题,然而这样就不能交错输出了。继而又想到了链表。然而写到后来发现进行不下去了。。。
其实我的理解也有错误。应该是以编号优先(比如说4 1/4 1应该输出4 1 2 3而不是2 3 4 1),由这个例子可以知道应该先以编号优先再以约束优先。
正确思路是拓扑+优先队列。这里还有个要拐弯的地方是,队列里的东西在最后输出的时候是反向的(不知道是怎么利用这一点想到思路的,那就让我废话一下来梳理思路好了。。。)
首先拿到很多约束(a在b前),而没有受到约束的点(包括约束放后的点)是可以随意放置的,而有约束的点却必须放在某一些点的前面。那不如把能放后面的点先放后面,这样也能贪心地保证可以满足较多的情况(为什么不正推?因为先以编号优先再以约束优先 )。那么什么样的点适合放后面?肯定是没有约束的点从小到大放后面。那么,当前没有约束的候选点里的最大点一定是确定放最后一个的,而这个点放完了又会导致一些与它约束的点变成了没有约束的点,又成了放后面的候选点,再从候选点里面选一个进行同样的操作。
所以这样子最后输出的点就会变成逆序的了。
现在有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
http://vj.hsacm.com/contest/view.action?cid=67#problem/A
其实我觉得蛮有难度的,深搜,链表都试过了,都是写到结尾被否决掉。归根结底是我思路不行。
说说我一开始的思路:先把先后的链构出来,然后发现会有很多这样平行不相关的链,不知道怎么交叉输出。然后想到用拓扑思想逐个变成符合条件输出,但是可能会出现前面遍历过的点因为后面的点删掉而变符合,然后又可以删。然而是继续往下遍历还是找到前面的点深层遍历我没搞清楚(其实这里有个因果关系)。然后我又想到用深搜解决这个问题,然而这样就不能交错输出了。继而又想到了链表。然而写到后来发现进行不下去了。。。
其实我的理解也有错误。应该是以编号优先(比如说4 1/4 1应该输出4 1 2 3而不是2 3 4 1),由这个例子可以知道应该先以编号优先再以约束优先。
正确思路是拓扑+优先队列。这里还有个要拐弯的地方是,队列里的东西在最后输出的时候是反向的(不知道是怎么利用这一点想到思路的,那就让我废话一下来梳理思路好了。。。)
首先拿到很多约束(a在b前),而没有受到约束的点(包括约束放后的点)是可以随意放置的,而有约束的点却必须放在某一些点的前面。那不如把能放后面的点先放后面,这样也能贪心地保证可以满足较多的情况(为什么不正推?因为先以编号优先再以约束优先 )。那么什么样的点适合放后面?肯定是没有约束的点从小到大放后面。那么,当前没有约束的候选点里的最大点一定是确定放最后一个的,而这个点放完了又会导致一些与它约束的点变成了没有约束的点,又成了放后面的候选点,再从候选点里面选一个进行同样的操作。
所以这样子最后输出的点就会变成逆序的了。
#include <bits/stdc++.h> using namespace std; typedef long long ll; vector<int> x[30005]; vector<int> v; int y[30005]; struct cmp{ bool operator()(const int &t1,const int &t2){ return t1<t2; //从大到小,与数组规则相反 } }; int main(){ int t; scanf("%d",&t); while(t--){ priority_queue<int,vector<int>,cmp> q; memset(y,0,sizeof(y)); v.clear(); int n,m,a,b; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) x[i].clear(); while(m--){ scanf("%d%d",&a,&b); x[b].push_back(a); y[a]++; } for(int i=1;i<=n;++i){ if(y[i]==0){ q.push(i); } } while(!q.empty()){ int w=q.top(); v.push_back(q.top()); q.pop(); for(int i=0;i<x[w].size();++i){ y[x[w][i]]--; if(y[x[w][i]]==0){ q.push(x[w][i]); } } } for(int i=v.size()-1;i>0;--i) printf("%d ",v[i]); printf("%d\n",v.front()); } return 0; }
相关文章推荐
- 例题6-4 UVa11988 静态链表
- Java图片上传压缩处理
- android开发之二维码
- MCPeerID
- 二叉树的镜像
- Android ANR问题分析
- android 制作简单的画板
- 一篇关于机器学习的温和指南
- Java快速入门【11~20待续】
- ajax请求在ie8下缓存问题
- 解析字符串为泛型的方法
- ARM -A9 基础学习()
- python[四]:python爬虫入门
- golang内存分配
- 关于Windows Boot Manager、Bootmgfw.efi、Bootx64.efi、bcdboot.exe 的详解
- UEFI启动视频详解:启动分析+N项操作实例
- 关于Windows Boot Manager、Bootmgfw.efi、Bootx64.efi、bcdboot.exe 的详解
- 反射得到对象类型后动态创建创建数组的方法
- 培训完结版
- leetcode 61. Rotate List