用以下的简单算法得到一个DAG的拓扑排序,而且,所有的拓扑排序都可以通过这个算法得到。设需要进行拓扑排序的图为G,已经完成拓扑排序的顶点构成序列q。
- 开始时,置图G1=G,q为空序列;
- 如果图G1是空图,则拓扑排序完成,算法结束,得到的序列q就是图G的一个拓扑排序;
- 在图G1中找到一个没有入边(即入度为0)的顶点v,将v放到序列q的最后(这样的顶点v必定存在,否则图G1必定有圈;因为图G有圈,故不是DAG);
- 从图G1中删去顶点v以及所有与顶点v相连的边e(通过将与v邻接的所有顶点的入度减1来实现),得到新的图G1,转到第二步。
以上摘自维基百科
以此题为例,用邻接表存储图
有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。
输入:输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。
输出:给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
Sample input:
4 3
1 2
2 3
4 3
Sample output:
1 2 4 3
#include <stdio.h> #include <malloc.h> #ifdef DEBUG #define MAX_NUM_TEAM -4 #endif #ifndef DEBUG #define MAX_NUM_TEAM 500 #endif /* 表结点 */ typedef struct Node1 { int iNum; /* 存储loser的序号 */ struct Node1 *next; /* 存储winner对应的loser结点 */ }EdgeNode; /* 头结点 */ typedef struct Node2 { int iNumTeam, iNumRemain; /* 分别表示总队数,未处理队 */ int iIndegree[MAX_NUM_TEAM+10]; /* 每个队对应顶点的入度 */ EdgeNode *sonNode[MAX_NUM_TEAM+10]; /* 子节点 */ }TPGraphNode; typedef struct LIST { int iNum; int _array[MAX_NUM_TEAM+10]; }List; int iNumMatch; TPGraphNode tpGraphNode; List list; /* 用于存放拓扑排序后的序列 */ /* 初始化 */ void Init() { int i; tpGraphNode.iNumRemain = tpGraphNode.iNumTeam; for (i = 1; i <= tpGraphNode.iNumTeam; i++) { tpGraphNode.iIndegree[i] = 0; tpGraphNode.sonNode[i] = NULL; } list.iNum = 0; } void Input() { int i, winner, loser; EdgeNode *p; for (i = 1; i <= iNumMatch; i++) { scanf("%d %d", &winner, &loser); tpGraphNode.iIndegree[loser]++; /* 入度+1 */ p = (EdgeNode *)malloc(sizeof(EdgeNode)); /* 申请新结点 */ p->iNum = loser; if (NULL == tpGraphNode.sonNode[winner]) /* winner第一次赢得比赛 */ { p->next = NULL; } else /* 前插 */ { p->next = tpGraphNode.sonNode[winner]; } tpGraphNode.sonNode[winner] = p; } } void TopologicalSort() { int i; EdgeNode *p, *q; while (tpGraphNode.iNumRemain-- > 0) { for (i = 1; i <= tpGraphNode.iNumTeam; i++) { if (0 == tpGraphNode.iIndegree[i]) /* 当找到入度为0的结点后,做以下处理,并跳出,从头开始查找 */ { list._array[list.iNum++] = i; p = tpGraphNode.sonNode[i]; /* 释放后继结点 */ while (NULL != p) { tpGraphNode.iIndegree[p->iNum]--; /* 对应的序号的入度-1 */ q = p->next; free(p); p = q; } tpGraphNode.iIndegree[i] = -1; /* 标记已处理过的入度为0的结点 */ break; } } } } void Output() { int i; for (i = 0; i < list.iNum; i++) { if (0 == i) { printf("%d", list._array[i]); } else { printf(" %d", list._array[i]); } } printf("\n"); } int main() { while (~scanf("%d %d", &tpGraphNode.iNumTeam, &iNumMatch)) { Init(); Input(); TopologicalSort(); Output(); } return 0; }
。