1365 - 算法7-12:有向无环图的拓扑排序
时间限制 : 1 秒
内存限制 : 32 MB
由某个集合上的一个偏序得到该集合上的一个全序,这个操作被称为拓扑排序。偏序和全序的定义分别如下:
若集合X上的关系R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。
设R是集合X上的偏序,如果对每个x,y∈X必有xRy或yRx,则称R是集合X上的全序关系。
由偏序定义得到拓扑有序的操作便是拓扑排序。
拓扑排序的流程如下:
1. 在有向图中选一个没有前驱的顶点并且输出之;
2. 从图中删除该顶点和所有以它为尾的弧。
重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。后一种情况则说明有向图中存在环。
采用邻接表存储有向图,并通过栈来暂存所有入度为零的顶点,可以描述拓扑排序的算法如下:

<span style="font-family:宋体;">在本题中,读入一个有向图的邻接矩阵(即数组表示),建立有向图并按照以上描述中的算法判断此图是否有回路,如果没有回路则输出拓扑有序的顶点序列。</span>
<span></span>
题目输入
输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。
以后的n行中每行有n个用空格隔开的整数0或1,对于第i行的第j个整数,如果为1,则表示第i个顶点有指向第j个顶点的有向边,0表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。
题目输出
如果读入的有向图含有回路,请输出“ERROR”,不包括引号。
如果读入的有向图不含有回路,请按照题目描述中的算法依次输出图的拓扑有序序列,每个整数后输出一个空格。
请注意行尾输出换行。
输入/输出样例
输入格式
4 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0
输出格式
3 0 1 2
C语言解答
#include<stdio.h> #define MAX_VERTEX_NUM 60 #define TRUE 1 #define FALSE 0 typedef int AdjType; typedef int Type; typedef struct { int num; AdjType A[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; }MGraph; void Push(int S[],int *n,int e) { S[(*n)++]=e; } Type Pop(int S[],int *n) { int e=S[--(*n)]; return e; } Type Empty(int S[],int *n) { if(!*n) return TRUE; else return FALSE; } void TopologicalSort(MGraph *G) { char indegree[MAX_VERTEX_NUM]={0}; int order[MAX_VERTEX_NUM]={0}; int k=0,count=0,n=0; int S[G->num]; for(int i=0;i<G->num;i++) { S[i]=-1; } for(int j=0;j<G->num;j++) { for(int i=0;i<G->num;i++) indegree[j]=indegree[j]+G->A[i][j]; if(!(indegree[j])) Push(S,&n,j); } while(!(Empty(S,&n))) { int top=Pop(S,&n); order[k++]=top; count++; for(int i=0;i<G->num;i++) { if((indegree[i]==1)&&(G->A[top][i]==1)) Push(S,&n,i); indegree[i]=indegree[i]-G->A[top][i]; } } if(count<G->num) { printf("ERROR\n"); } else { for(int i=0;i<k;i++) printf("%d ",order[i]); printf("\n"); } } int main() { MGraph G; int N; scanf("%d",&N); G.num=N; AdjType a[N][N]; for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { scanf("%d",&a[i][j]); } } for(int i=0;i<N;i++) { for(int j=0;j<N;j++) { G.A[i][j]=a[i][j]; } } TopologicalSort(&G); return 0; }
C++解答
#include <cstdio> #include <cstdlib> #include <stack> #include <algorithm> using namespace std; const int MAXN = 50; int mat[MAXN][MAXN], output[MAXN], indegree[MAXN]; int n, outputCnt, current; stack<int> st; bool TopologicalSort() { outputCnt = 0; while (!st.empty()) st.pop(); for (int i = 0;i < n;i++) indegree[i] = 0; for (int i = 0;i < n;i++) { for (int j = 0;j < n;j++) { if (mat[i][j]) indegree[j]++; } } for (int i = 0;i < n;i++) { if (indegree[i] == 0) { st.push(i); } } while (!st.empty()) { current = st.top(); st.pop(); output[outputCnt++] = current; for (int i = 0;i < n;i++) { if (mat[current][i]) { indegree[i]--; if (indegree[i] == 0) { st.push(i); } } } } return (outputCnt == n); } int main() { scanf("%d", &n); for (int i = 0;i < n;i++) { for (int j = 0;j < n;j++) { scanf("%d", &mat[i][j]); } } if (TopologicalSort()) { for (int i = 0;i < n;i++) { printf("%d ", output[i]); } puts(""); } else { puts("ERROR"); } return 0; }