AOV网与拓扑排序
㈠AOV网概念
在有向图中,若用顶点表示活动,有向边表示活动顺序,称该有向图为顶点表示活动的网络,简称AOV网。在AOV网中,若从顶点i到顶点j之间存在一条有向路径,称顶点i是顶点j的前驱,或顶点j是顶点i的后继。若<i,j>是图中的边,则称i是j的直接前驱,j是i直接后继。
㈡AOV网的实际意义
在一个大的工程中,常被划分为许多较小的子工程,在整个工程实施过程中,有些活动的开始是以它的所有前序活动结束为先决条件的,而有些则没有先决条件,可以安排在任意时间开始。AOV网就是一种可以形象的反映出整个工程中各个活动之间前后关系的有向图。
㈢拓扑排序
在有向图G=(V,E)中,对于V中顶点的线性序列,若在G中从顶点Vi到Vj有一条路径,则在序列中Vi必在Vj之前,称该序列为G的一个拓扑序列。构造有向图的一个拓扑序列的过程称为称为拓扑排序。
说明:
⑴在AOV网中,若不存在回路,则所有活动可排成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,那么该序列称为拓扑序列。
⑵拓扑序列不是唯一的。
⑶AOV网并不一定都有拓扑序列。AOV网中不能出现有向回路(或有向环),若出现了有向环,则意味着某项活动以自己为先决条件,这是不对的,工程将无法进行。程序将出现死循环。因此,对于给定的AOV网,应判断它是否存在有向环。判断方法是对AOV网进行拓扑排序,若该序列中包含AOV网中全部顶点,则无环,否则存在有向环,该网代表的工程是不可行的。
⑷拓扑排序的实际意义为:若按照该拓扑序列的顶点次序进行每项活动,就能保证进行每一项活动时,其所有前驱活动均已完成,从而使工程顺利执行。
㈣拓扑排序算法步骤
⑴在AOV网中选取一个入度为0的顶点(没有前驱),且输出之;
⑵在AOV网中删除此顶点及该顶点发出来的所有有向边;
⑶重复⑴、⑵两步,直至AOV网中所有顶点均输出或不存在入度为0的点。
参考代码:
代码一,二维数组建图;
#include<stdio.h>
#include<string.h>
int map[1010][1010];
int indegree[1010];
int ans[1010];
void toposort(int n)
{
for(int i=1;i<=n;i++) //对每个点进行查找
{
int j=1;
while(indegree[j]) //从小到大查找到无前驱的
j++;
ans[i]=j; //存放到数组中,也可直接输出之
indegree[j]=-1; //将入度记为-1,防止再次被查找到
for(int k=1;k<=n;k++) //更新与查找到的点有关的点的前驱
if(map[j][k])
indegree[k]--;
}
}
int main()
{
int n,m; //有n个点,m条边
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(map,0,sizeof(map)); //初始化
memset(indegree,0,sizeof(indegree));
for(int i=0;i<m;i++)
{
int p1,p2;
scanf("%d%d",&p1,&p2);
if(!map[p1][p2]) //去重操作
{
indegree[p2]++; //存放p2的前驱值
map[p1][p2]=1; //p2的前驱为p1,做标记
}
}
toposort(n);
for(int i=1;i<n;i++) //ans数组中存放的是一种拓扑序列
printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
return 0;
}
代码二,链式建图;
#include<stdio.h>
#include<string.h>
int head[5100];
int indegree[5100];
int ans[5100];
struct node{
int to;
int next;
}a[5100];
void toposort(int n)
{
for(int i=1;i<=n;i++)
{
int j=1;
while(indegree[j])
j++;
ans[i]=j;
indegree[j]=-1;
for(int k=head[j];k!=-1;k=a[k].next)
{
indegree[a[k].to]--;
}
}
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(head,-1,sizeof(head));
memset(indegree,0,sizeof(indegree));
for(int i=1;i<=m;i++)
{
int p1,p2;
scanf("%d%d",&p1,&p2);
a[i].to=p2;
a[i].next=head[p1];
head[p1]=i;
indegree[p2]++;
}
toposort(n);
for(int i=1;i<n;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
return 0;
}
代码三,队列实现;
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int degree[5100];
int map[510][510];
void toposort(int n)
{
priority_queue<int,vector<int>,greater<int> >q;
for(int i=1;i<=n;i++)
if(degree[i]==0)
q.push(i);
int flag=1;
while(!q.empty())
{
int top=q.top();q.pop();
degree[top]=-1;
if(flag)
printf("%d",top);
else
printf(" %d",top);
flag=0;
for(int j=1;j<=n;j++)
if(map[top][j])
{
degree[j]--;
if(degree[j]==0)
{
q.push(j);
}
}
}
printf("\n");
}
int main()
{
int n,m,p1,p2;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(map,0,sizeof(map));
memset(degree,0,sizeof(degree));
for(int i=0;i<m;i++)
{
scanf("%d%d",&p1,&p2);
if(map[p1][p2]==0)
{
map[p1][p2]=1;
degree[p2]++;
}
}
toposort(n);
}
return 0;
}