HDU 1285 确定比赛名次
确定比赛名次
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 17915 Accepted Submission(s): 7169
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队。
Output
给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
Sample Input
4 3
1 2
2 3
4 3
Sample Output
1 2 4 3
Author
SmallBeer(CML)
Source
Recommend
lcy
-------------------------------------------------------------------------------------------------------------------------
我的错误解法
#include <bits/stdc++.h> using namespace std; const int N(500+5); vector<int> g[N]; bool vis[N]; int topo[N], tot; void dfs(int u){ vis[u]=1; for(int i=0; i<g[u].size(); i++){ int &v=g[u][i]; if(vis[v]) continue; dfs(v); } topo[--tot]=u; } int main(){ for(int n, m; ~scanf("%d%d", &n, &m);){ for(int i=1; i<=n; i++) g[i].clear(); for(int u, v; m--;) scanf("%d%d", &u, &v), g[u].push_back(v); for(int i=1; i<=n; i++) sort(g[i].begin(), g[i].end(), greater<int>()); memset(vis, 0, sizeof(vis)); tot=n; for(int i=n; i; i--) if(!vis[i]) dfs(i); printf("%d", topo[0]); for(int i=1; i<n; i++) printf(" %d", topo[i]); puts(""); } }
首先总的想法是DFS拓扑排序,由于题目要求输出字典序最小的排列,对DFS的顺序做一些修改:
(1)将每个节点的邻接表从大到小排序
(2)在主函数内,按照节点编号从大到小的顺序调用DFS
这两个修改虽然方向是对的,但还是有问题的。
比如,样例
5 4
5 2
2 4
5 3
3 1
正确输出是
5 2 3 1 4
但我的代码输出:
5 2 4 3 1
这个题目的输出要解决的问题是:
保证先后关系不确定的节点中,序号小的在前。
(注意,上面用的词是先后关系,而非胜负关系。因为,假如知道了 A胜B, B胜C 那么A, B, C三者的先后一定是 A B C 但A和C的胜负关系是不知道的。)
能否在不改变DFS框架的前提下,使输出正确呢?
---------------------------------------------------------------------------------------
正解是:迭代
每次选择入度为0且编号最小的点u输出,将u删除,并将u的临接表中的点的入度减一。
(这种解法不需要处理重边)
#include <bits/stdc++.h> using namespace std; const int N(500+5); vector<int> g[N]; int in[N]; int main(){ for(int n, m; ~scanf("%d%d", &n, &m);){ for(int i=1; i<=n; i++) g[i].clear(); memset(in, 0, sizeof(in)); for(int u, v; m--;) scanf("%d%d", &u, &v), g[u].push_back(v), in[v]++; for(int i=0; i<n; ) for(int u=1; u<=n; u++){ if(in[u]==0){ if(!i++) printf("%d", u); else printf(" %d", u); in[u]=-1; for(int j=0; j<g[u].size(); j++){ int &v=g[u][j]; in[v]--; } break; } } puts(""); } }
还可用堆优化
#include <bits/stdc++.h> using namespace std; const int N(500+5); vector<int> g[N]; int in[N]; typedef pair<int,int> P; priority_queue<P, vector<P>, greater<P> > que; int main(){ for(int n, m; ~scanf("%d%d", &n, &m);){ for(int i=1; i<=n; i++) g[i].clear(); memset(in, 0, sizeof(in)); for(int u, v; m--;) scanf("%d%d", &u, &v), g[u].push_back(v), in[v]++; for(int i=1; i<=n; i++) que.push({in[i], i}); bool first=true; while(!que.empty()){ P top=que.top(); que.pop(); int &u=top.second; if(in[u]!=top.first) continue; if(first) printf("%d", u), first=false; else printf(" %d", u); for(int i=0; i<g[u].size(); i++){ int &v=g[u][i]; que.push({--in[v], v}); } } puts(""); } }