拓扑排序--确定比赛名次(模板题)

Posted very-beginning

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了拓扑排序--确定比赛名次(模板题)相关的知识,希望对你有一定的参考价值。

拓扑排序的过程大概是这样的:
① 选择一个入度为0 的结点并直接输出。
② 删除这个结点以及与它关联的所有边。
③ 重复步骤①和②,直到找不到入度为0 的结点。

在一个有向图中,对所有的节点进行排序,要求没有一个节点指向它前面的节点。先统计所有节点的入度,对于入度为0的节点就可以分离出来,然后把这个节点指向的节点的入度减一。一直做改操作,直到所有的节点都被分离出来。如果最后不存在入度为0的节点,那就说明有环,不存在拓扑排序,也就是很多题目的无解的情况。
*1:删除1或2输出
技术图片

 

 *2:删除2或3以及对应边

技术图片

 

 

 *3:删除3或者4以及对应边

技术图片技术图片

 

* 3:重复以上规则步骤

技术图片

 

 

通过邻接矩阵来实现的代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 int ans[510][510];///邻接矩阵,记录二者是否有关联
 4 int n,indegree[510];///记录节点个数
 5 int queue[510];///保存拓扑
 6 void topsort()
 7 {
 8     int i,j,top,k=0;
 9     for(j=0; j<n; ++j)///遍历n次
10     {
11         for(i=1; i<=n; ++i)
12         {
13             if(indegree[i]==0)///找到入度为0的节点
14             {
15                 top=i;
16                 break;
17             }
18         }
19         queue[k++]=top;///当前第一名入队列,也可以直接输出
20         indegree[top]=-1;///该节点的入度更新为-1,避免重复入队列
21         for(i=1; i<=n; ++i)
22         {
23             if(ans[top][i])///删除与该店关联的边
24                 indegree[i]--;
25         }
26     }
27     for(i=0; i<k-1; ++i)
28         printf("%d ",queue[i]);
29     printf("%d
",queue[n-1]);
30 }
31 
32 int main()
33 {
34     int i,a,b,m;
35     while(scanf("%d%d",&n,&m)!=EOF)
36     {
37         memset(indegree,0,sizeof(indegree));///数组初始化为0
38         memset(ans,0,sizeof(ans));///数组初始化为0
39         for(i=0; i<m; ++i)
40         {
41             scanf("%d%d",&a,&b);
42             if(ans[a][b]==0)
43             {
44                 ans[a][b]=1;///二者有关联
45                 indegree[b]++;///记录前驱数量
46             }
47         }
48         topsort();
49     }
50     return 0;
51 }

 

 接下来是一道例题:

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
给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
这道题相当于对含有n个顶点的图进行拓扑排序并输出
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #define V 510 
 5 int G[V][V];    //
 6 int degree[V];  //记录各顶点的入度
 7 void topological_sort(int n) 
 8 {    
 9     int i, j, k;    
10     for(i = 1; i <= n; i++){        
11         for(j = 1; j <= n; j++){            
12             if(degree[j] == 0){     //找到入度为0的顶点                
13                 printf("%d", j);    //输出                
14                 degree[j]--;        //将其入度减为-1                
15                 k = j;              //用k记录此顶点                
16                 break;            
17             }        
18         }        
19         for(j = 1; j <= n; j++){            
20             if(G[k][j] == 1){   //找到被此顶点打败过的顶点                
21                 G[k][j] = 0;    //标记                
22                 degree[j]--;    //将找到的顶点的入度减一            
23             }        
24         }        
25         if(i != n)            
26             printf(" ");        
27         else            
28             printf("
");    
29     }
30 }
31 int main(){    
32     int n;  
33     int m;
34     while(scanf("%d%d", &n, &m) != EOF){        
35         memset(G, 0, sizeof(G));            //图的初始化        
36         memset(degree, 0, sizeof(degree));  //顶点入度的初始化        
37         while(m--){            
38             int u, v;            
39             scanf("%d%d", &u, &v);  //u打败了v            
40             if(G[u][v] == 0){       /*去重这里要记录的是v被多少人打败过 */                
41                 G[u][v] = 1;    //u打败过v                
42                 degree[v]++;    //顶点v的入度加一            
43             }        
44         }        
45         topological_sort(n);
46     }    
47     return 0;
48 }

 

 
 

以上是关于拓扑排序--确定比赛名次(模板题)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

题目1449:确定比赛名次(拓扑排序问题)

HDU[1285]确定比赛名次 拓扑排序

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