正向与反向拓扑排序的区别(hdu 1285 确定比赛名次和hdu 4857 逃生)
Posted zgncbsylm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了正向与反向拓扑排序的区别(hdu 1285 确定比赛名次和hdu 4857 逃生)相关的知识,希望对你有一定的参考价值。
确定比赛名次
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 16 Accepted Submission(s) : 9
Problem Description
有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。
Input
输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。
逃生
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 20 Accepted Submission(s) : 9
Problem Description
糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。
现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。
同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。
负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。
那么你就要安排大家的顺序。我们保证一定有解。
现在有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
Output
给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。 其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
Sample Input
4 3
1 2
2 3
4 3
Sample Output
1 2 4 3
两者看着并没什么大的区别。
但前者是用最普通的拓扑排序,而后者需要反着来。
对普通的拓扑排序,由于题目需要按序,所以使用优先队列即可,将没有 前点 (即入度)的点入列,用这几个点的路径减少其他点的入度,然后将入度为0的入队,就行了。
而对于第二题,则由于要求的不同(先考虑1在尽量前,再考虑2尽量前。。。),我们将后点设为入度,同样的方法排序,反向输出即可。
可能有人会觉得两者差不多。
这里给个例子。
5 2(n,m)
5 1
4 2
正向给出的答案是3 4 2 5 1
反向给出的答案是1 2 3 4 5
理解一下
以下是代码:
1285 确定比赛名次:
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define me(a,b) memset(a,b,sizeof(a)) #define N 5100 typedef long long ll; using namespace std; int in[N],head[N],n,m,cnt,s,e; priority_queue<int,vector<int>,greater<int> > q; vector<int> ans; struct co { int e,pre; }mp[N]; void init() { me(head,-1); cnt=0; me(in,0); while(!q.empty()) q.pop(); ans.clear(); } void add(int ss,int ee) { mp[cnt].e=ee; mp[cnt].pre=head[ss]; head[ss]=cnt++; } int main() { //freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)) { init(); while(m--) { scanf("%d%d",&s,&e); in[e]++; add(s,e); } for(int i=1;i<=n;i++) { if(in[i]==0) { q.push(i); } } while(!q.empty()) { int f=q.top(); ans.push_back(f); q.pop(); for(int i=head[f]; i!=-1; i=mp[i].pre) { in[mp[i].e]--; if(in[mp[i].e]==0) { q.push(mp[i].e); } } } for(int i=0;i<ans.size();i++) { if(i) cout<<‘ ‘; cout<<ans[i]; } cout<<endl; } }
4857:
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define me(a,b) memset(a,b,sizeof(a)) #define N 100010 typedef long long ll; using namespace std; int in[30100],head[N],n,m,cnt,s,e; priority_queue<int> q; vector<int> ans; struct co { int e,pre; }mp[N]; void init() { me(head,-1); me(in,0); cnt=0; while(!q.empty()) q.pop(); ans.clear(); } void add(int ss,int ee) { mp[cnt].e=ee; mp[cnt].pre=head[ss]; head[ss]=cnt++; } int main() { //freopen("in.txt","r",stdin); int T; cin>>T; while(T--) { init(); scanf("%d%d",&n,&m); while(m--) { scanf("%d%d",&s,&e); in[s]++; add(e,s); } for(int i=1;i<=n;i++) { if(in[i]==0) { q.push(i); } } while(!q.empty()) { int f=q.top(); ans.push_back(f); q.pop(); for(int i=head[f]; i!=-1; i=mp[i].pre) { in[mp[i].e]--; if(in[mp[i].e]==0) { q.push(mp[i].e); } } } for(int i=ans.size()-1;i>-1;i--) { cout<<ans[i]; if(i) cout<<‘ ‘; } cout<<endl; } }
以上是关于正向与反向拓扑排序的区别(hdu 1285 确定比赛名次和hdu 4857 逃生)的主要内容,如果未能解决你的问题,请参考以下文章