您的位置:首页 > 其它

HDU 1285 确定比赛名次(拓扑排序)

2018-03-08 19:40 176 查看
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#include <stdio.h>
#include <string.h>
int map[1001][1001],vis[1001],buf[1001];
int main ()
{
int m,n;
// printf ("请输入节点树和路径数:\n");
while (~scanf ("%d%d",&m,&n)){
int i,j;
memset(vis,0,sizeof vis);
memset(map,0,sizeof map);
// printf ("请输入路径:\n");
for (i = 1;i <= n; i++){
int a,b;
scanf ("%d%d",&a,&b);
if (map[a] == 0){
map[a][b] = 1;
vis[b]++;
}
}
/* printf ("图的邻接矩阵为:\n");
for (i = 1;i <= m; i++){
for (j = 1;j <= m; j++){
printf ("%d ",map[i][j]);
}
printf ("\n");
}*/
int cur=0,k,p;
for (k = 0;k < m; k++){//拓扑排序的核心算法,且外层循环无法省略
for (i = 1;i <= m; i++){//寻找度为0的节点
if (!vis[i]){
p=i;
buf[cur++] = i;
vis[i] = -1;
break;
}
}
for (j = 1;j <= m; j++){//删除边以及更新节点的度。
if (map[p][j]){
map[p][j] = 0;
vis[j]--;
}
}
}
// printf ("排序结果为:\n");
for (i = 0;i < cur; i++)
printf ("%d%c",buf[i],i == cur-1?'\n':' ');
// printf ("请输入节点树和路径数:\n");
}
return 0;
}首先注意只有有向图可以使用拓扑排序且不存在环。
其次拓扑排序的核心是寻找度为0的节点,所以必须最外层一个循环m次每找到一次目标节点就做一次删除更新操作。而以下操作是错误的for (i = 1;i <= m ;i++){
if (!vis[i]){
buf[cur++]=i;
vis[i]--;
for (j = i;j <= m; j++){
if (map[p][j]){
map[p][j] = 0;
vis[j]--;
}
}
}
}
这样做的后果是有些节点无法标记到输出的队列。



如这个图中,按顺序来找到C1->C2->C3->C5。这时[b]C4将被跳过!
因此正确的做法应该是为每找到一个节点就重新寻找,以防止遗漏。值得注意的是有几个节点就要重复操作几次!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: