由某个集合上的一个偏序得到该集合上的一个全序,这个操作被称为拓扑排序。偏序和全序的定义分别如下:
若集合X上的关系R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。
设R是集合X上的偏序,如果对每个x,y∈X必有xRy或yRx,则称R是集合X上的全序关系。
由偏序定义得到拓扑有序的操作便是拓扑排序。
拓扑排序的流程如下:
1. 在有向图中选一个没有前驱的顶点并且输出之;
2. 从图中删除该顶点和所有以它为尾的弧。
重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。后一种情况则说明有向图中存在环。
采用邻接表存储有向图,并通过栈来暂存所有入度为零的顶点,可以描述拓扑排序的算法如下:
在本题中,读入一个有向图的邻接矩阵(即数组表示),建立有向图并按照以上描述中的算法判断此图是否有回路,如果没有回路则输出拓扑有序的顶点序列。
Input Description
输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。
以后的n行中每行有n个用空格隔开的整数0或1,对于第i行的第j个整数,如果为1,则表示第i个顶点有指向第j个顶点的有向边,0表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。
Output Description
如果读入的有向图含有回路,请输出“ERROR”,不包括引号。
如果读入的有向图不含有回路,请按照题目描述中的算法依次输出图的拓扑有序序列,每个整数后输出一个空格。
请注意行尾输出换行。
Sample Input
4 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0
Sample Output
3 0 1 2
#include<stdio.h>
#include<stdlib.h>
typedef struct Stack
{
int *top;
int *base;
int Size;
}Stack;
int n,a[50][50];
int visit[50]={0};
void InitStack(Stack *b)
{
b->base=(int*)malloc(sizeof(int)*100);
b->top=b->base;
b->Size=100;
}
void F(int *b)//关键点
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(a[i][j])
visit[j]++;
}
void push(Stack *S,int i)
{
(*S->top++)=i;
}
int pop(Stack *S)
{
return *(--S->top);
}
int EmptyStack(Stack S)
{
if(S.base==S.top)
return 1;
return 0;
}
void Look()
{
Stack S;
InitStack(&S);
F(visit);
for(int i=0;i<n;i++)
if(!visit[i])
push(&S,i);
int ans=0,i;
while(!EmptyStack(S))
{
i=pop(&S);
printf("%d ",i);
ans++;
for(int j=0;j<n;j++)
if(a[i][j]==1)
{
visit[j]--;
if(visit[j]==0)
push(&S,j);
}
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&a[i][j]);
Look();
}
/*void F(int *b)关键的东西查找入度的点对于有入度的++最后输出是入度为零的点*/