一般一个工程可以分成若干个子工程,这些子工程称为活动。实际上,可以用有向图来表示一个工程,用有向边<u,v>表示活动u必须先于活动v完成。这种有向图叫做顶点表示活动的网络,记作AOV网络(Activity On Vertices)。u成为v的直接前驱,v叫做u的直接后继,如果存在路径<u,u1,u2,u3.......v>,则称u是v的前驱,v是u的后继。任何活动不能以他自己为前驱或者后继,这种特性称为反自反性,AOV网络中不能出现有向回路。不含有向回路的有向图称为有向无环图,对于给定的AOV网络,必须先判断它是否是有向无环图。
拓扑排序:判断有向无环图的方法是对AOV网络构造它的拓扑有序序列,即将各个顶点排列成一个线性有序的序列。
实现方法:(1)从AOV网络中选取一个入度为0的顶点并输出
(2)从AOV网络中删除该顶点及该顶点发出的所有边
(3)重复步骤(1)(2),直到找不到入度为0的顶点
按照上述方法进行拓扑排序,其结果有两种情形:(1)所有的顶点都被输出,也就是整个拓扑排序完成了 (2)仍有顶点没有被输出,但剩下的图中再也没有入度为0的顶点,这样拓扑排序就不能再继续进行下去了,说明此图是有向环图。
例题:对输入的有向图进行拓扑排序,并输出一个拓扑排序序列。如果存在有向环,则给出提示信息。
输入描述:先输入顶点数n和边数m,然后输出m条边。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define MAXN 10
struct ArcNode
{
int to;
ArcNode *next;
};
int n,m;
ArcNode *list[MAXN];
int count[MAXN];
char output[100];
void TopSort();
int main()
{
int i,j;
int u,v,w;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0) break;
memset(list,0,sizeof(list));
memset(count,0,sizeof(count));
memset(output,0,sizeof(output));
ArcNode *temp;
for(i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
u--;
v--;
count[v]++;
temp=new ArcNode;
temp->to=v;
temp->next=NULL;
if(list[u]==NULL)
list[u]=temp;
else
{
temp->next=list[u];
list[u]=temp;
}
}
TopSort();
for(i=0;i<n;i++)
{
temp=list[i];
while(temp!=NULL)
{
list[i]=temp->next;
delete temp;
temp=list[i];
}
}
}
return 0;
}
void TopSort()///拓扑排序
{
int i,j,top=-1;
ArcNode *temp;
bool bcycle=false;/// 是否存在有向环的标志
int pos=0;///写入output数组的位置
for(i=0;i<n;i++)///入度为0的点入栈
{
if(count[i]==0)
{
count[i]=top;
top=i;
}
}
for(i=0;i<n;i++)
{
if(top==-1)///栈为空,存在有向回路
{
bcycle=true;
break;
}
else
{
j=top;///栈顶点j出栈
top=count[top];
pos+=sprintf(output+pos,"%d ",j+1);///返回值为这一次写入的字符串的长度
temp=list[j];
///遍历顶点j的边链表,每条出边的终点入度减一
while(temp!=NULL)
{
int k=temp->to;
count[k]--;
if(count[k]==0)
{
count[k]=top;
top=k;
}
temp=temp->next;
}
}
}
if(bcycle)
printf("Network has a cycle\n");
else
{
int len=strlen(output);
output[len-1]=0;///去掉最后的空格
printf("%s\n",output);
}
}