有向无环图

AOV

AOV网:在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,称这样的有向图为顶点表示活动的网,简称AOV网。
AOV网特点
1.AOV网中的弧表示活动之间存在的某种制约关系。
2.AOV网中不能出现回路 。

拓扑序列:

设G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列v1, v2, …, vn称为一个拓扑序列,当且仅当满足下列条件:若从顶点vi到vj有一条路径,则在顶点的拓扑序列中顶点vi必在顶点vj之前。

拓扑排序:

对一个有向图构造拓扑序列的过程称为拓扑排序 。
拓扑序列使得AOV网中所有应存在的前驱和后继关系都能得到满足。

基本思想:

⑴ 从AOV网中选择一个没有前驱的顶点并且输出;
⑵ 从AOV网中删去该顶点,并且删去所有以该顶点为尾的弧;
⑶ 重复上述两步,直到全部顶点都被输出,或AOV网中不存在没有前驱的顶点。

设计数据结构

在这里插入图片描述
在这里插入图片描述

思想

(1)找G中无前驱的顶点
查找indegree [i]为零的顶点vi;
(2)修改邻接于顶点i的顶点的入度(删除以i为起点的所有弧)
对链在顶点i后面的所有邻接顶点k,将对应的indegree[k] 减1。
为了避免重复检测入度为零的顶点,可以再设置一个辅助栈,若某一顶点的入度减为0,则将它入栈。每当输出某一入度为0的顶点时,便将它从栈中删除。

算法

  1. 栈S初始化;累加器count初始化;
  2. 扫描顶点表,将没有前驱的顶点压栈;
  3. 当栈S非空时循环
    3.1 vj=退出栈顶元素;输出vj;累加器加1;
    3.2 将顶点vj的各个邻接点的入度减1;
    3.3 将新的入度为0的顶点入栈;
  4. if (count<vertexNum) 输出有回路信息;
void TOpSort(){
int  top=-1, count=0;
for(int i=0;i<vertexnum;i++)
     if(adjlist[i].in==0) s[++top]=i;
while(top!=-1){
    j=s[top--]; cout <<adjlist[j].vertext;   count++;
    p=adjlist[j].firstedge;
    while(p!=NULL){
          k=p->adjvex; adjlist[k].in--;
         if(adjlist[k].in==0) s[top++]=k;
         p=p->next;
      } 
}
If (count<vertexNum) cout<<“有回路”;
}

AOE

1、AOE网可以回答下列问题:

  • 完成整个工程至少需要多少时间?
    从始点到终点的路径可能不止一条,只有各条路径上所有活动都完成了,整个工程才算完成。
    因此,完成整个工程所需的最短时间取决于从始点到终点的最长路径长度,即这条路径上所有活动的持续时间之和。
    这条路径长度最长的路径就叫做关键路径

  • 为缩短完成工程所需的时间, 应当加快哪些活动?

2、关键路径:在AOE网中,从始点到终点具有最大路径长度(该路径上的各个活动所持续的时间之和)的路径称为关键路径。

3、关键活动:关键路径上的活动称为关键活动。

4、要找出关键路径,必须找出关键活动, 即不按期完成就会影响整个工程完成的活动。

5、首先计算以下与关键活动有关的量:
⑴ 事件的最早发生时间ve[k]
⑵ 事件的最迟发生时间vl[k]
⑶ 活动的最早开始时间e[i]
⑷ 活动的最晚开始时间l[i]
最后计算各个活动的时间余量 l[k] - e[k],时间余量为0者即为关键活动。

6、存储结构的选择:
为处理方便,同时采用了邻接矩阵和边集数组两种存储结构。
邻接矩阵可以方便的查找邻接点,完成时间的最早和最晚发生时间的计算。
边集数组可以方便的计算时间的活动的最晚发生时间

struct Edge{
	int from;
	int to;
	int e;
	int l;
};

class Grap{
	int vertexnum,e;
	int **adjlist;   //邻接矩阵
	int start,end;
	Edge *edge;  //边集数组
public:
	Grap(int n,int e);
	int  path();
};

⑴ 事件的最早发生时间ve[k]

ve[k]是指从始点开始到顶点vk的最大路径长度。这个长度决定了所有从顶点vk发出的活动能够开工的最早时间。最大保证先期活动全部结束。
在这里插入图片描述

     q.push(0);//源点事件入队
	for(j=0;j<vertexnum;j++)	{  //初始化每个事件最早发生时间
		ve[j]=0;	visit[j]=0;	}
	visit[0]=1;	
     while(!q.empty())	{		
		i=q.front();       //利用标准模板库中的队列实现
		q.pop();
		for(j=0;j<vertexnum;j++){//计算i的邻接点的ve
			if(adjlist[i][j]!=9999 && ve[i]+adjlist[i][j]>ve[j] ){
				ve[j]=ve[i]+adjlist[i][j];
				if(!visit[j])   //如果j没有被访问过,顶点j入队
					q.push(j);
				visit[j]=1;
			}
		}
	}

⑵ 事件的最迟发生时间vl[k]

vl[k]是指在不推迟整个工期的前提下,事件vk允许的最晚发生时间。
最小同样保证如果在这一时刻发生事件,后续的工作可以正常进行。 在这里插入图片描述

    q.push(vertexnum-1);
	for(j=0;j<vertexnum;j++)	{
		vl[j]=ve[vertexnum-1];	visit[j]=0;	}
    while(!q.empty())	{
		i=q.front();
		q.pop();
		for(j=0;j<vertexnum;j++)	{
			if(adjlist[j][i]!=9999 && vl[i]-adjlist[j][i]<vl[j] ){
				vl[j]=vl[i]-adjlist[j][i];
				if(!visit[j])
					q.push(j);
				visit[j]=1;
			}
		}
	}

⑶ 活动的最早开始时间e[i]

若活动ai是由弧<vk , vj>表示,则活动ai的最早开始时间应等于事件vk的最早发生时间。因此,有:e[i]=ve[k]

	for(i=0;i<e;i++)
	{
		edge[i].e=ve[edge[i].from];
	}

⑷ 活动的最晚开始时间l[i]

活动ai的最晚开始时间是指,在不推迟整个工期的前提下, ai必须开始的最晚时间。
若ai由弧<vk,vj>表示,则ai的最晚开始时间要保证事件vj的最迟发生时间不拖后。
因此,有:l[i]=vl[j]-len<vk, vj>

	for(i=0;i<e;i++)
	{
		edge[i].e=ve[edge[i].from];
		edge[i].l=vl[edge[i].to]-adjlist[edge[i].from][edge[i].to];
	}
	for(i=0;i<e;i++)
	{
		edge[i].e=ve[edge[i].from];
		edge[i].l=vl[edge[i].to]-adjlist[edge[i].from][edge[i].to];
		if(edge[i].e==edge[i].l)
			cout<<edge[i].from<<"  "<<edge[i].to<<endl;
	}

猜你喜欢

转载自blog.csdn.net/qq_45654306/article/details/103334816
今日推荐