游客 Signup | Login
中文 | En

1365 - 算法7-12:有向无环图的拓扑排序

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

<span style="font-family:宋体;">在本题中,读入一个有向图的邻接矩阵(即数组表示),建立有向图并按照以上描述中的算法判断此图是否有回路,如果没有回路则输出拓扑有序的顶点序列。</span>

<span></span>

Input

输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。
以后的n行中每行有n个用空格隔开的整数0或1,对于第i行的第j个整数,如果为1,则表示第i个顶点有指向第j个顶点的有向边,0表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。

Output

如果读入的有向图含有回路,请输出“ERROR”,不包括引号。
如果读入的有向图不含有回路,请按照题目描述中的算法依次输出图的拓扑有序序列,每个整数后输出一个空格。
请注意行尾输出换行。

Examples

Input

4
0 1 0 0
0 0 1 0
0 0 0 0
0 0 1 0

Output

3 0 1 2 

Hint

在本题中,需要严格的按照题目描述中的算法进行拓扑排序,并在排序的过程中将顶点依次储存下来,直到最终能够判定有向图中不包含回路之后,才能够进行输出。
另外,为了避免重复检测入度为零的顶点,可以通过一个栈结构维护当前处理过程中入度为零的顶点。

Solution 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;  
} 

Solution 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;
}

Hint

在本题中,需要严格的按照题目描述中的算法进行拓扑排序,并在排序的过程中将顶点依次储存下来,直到最终能够判定有向图中不包含回路之后,才能够进行输出。
另外,为了避免重复检测入度为零的顶点,可以通过一个栈结构维护当前处理过程中入度为零的顶点。

Time Limit 1 second
Memory Limit 32 MB
Discuss Stats
上一题 下一题