求AOE网的关键路径



AOE-网 (Activity on Edge),即边表示活动的网。若在带权的有向无环图G中,顶点表示事件(Event),弧表示活动(Activity),权(Weight)表示持续的时间,则此有向图称为边表示活动的网,即AOE-网。
AOE- 网的用途: 用来估算工程的完成时间
分析关键路径的目的:辨别哪些是关键活动,以便争取提高关键活动的工效, 缩短整个工期。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stack>
using namespace std;
#define MAXNODE 1000// 图中顶点的最大个数
typedef int infotype;
typedef int vertype;
struct ArcNode//边节点类型
{
    int adjvex;//该边的终点编号
    ArcNode *next;//指向下一条边的指针
    infotype info;//该边的相关信息
};
struct VerNode//表头结点
{
    vertype vertex;// 顶点信息
    ArcNode *firstarc;// 指向第一个邻接点的指针
};
struct AlGraph//邻接表
{
    VerNode vertices[MAXNODE];//邻接表
    int vexnum,arcnum;// 顶点和边的数目
};
//事件的:ve最早发生时间,vl最迟发生时间;活动的:e最早加工时间,l最迟加工时间
int ve[MAXNODE],vl[MAXNODE],e,l;
AlGraph CreatAdjList(AlGraph g)//建立有向图的邻接表存储结构
{
    int n;
    cout<<"输入顶点个数:"<<endl;
    cin>>n;
    cout<<"输入顶点的名称:"<<endl;
    for(int i=1;i<=n;i++)
    {
        cin>>g.vertices[i].vertex;//输入顶点信息
        g.vertices[i].firstarc=NULL;//初始化每个链表为空
    }
    int v1,v2,info;
    cout<<"输入图的边以及权值,两个顶点之一为0,表示输入结束。"<<endl;
    cin>>v1>>v2>>info;//输入一条边依附的两个顶点序号,以及权值
    int e=0;//图的边数
    while(v1!=0&&v2!=0)//题目要求两顶点之一为0表示结束
    {
        //i=GraphLocateVertex(g,v1);
        //j=GraphLocateVertex(g,v2);
        ArcNode *p= (ArcNode*)malloc(sizeof(ArcNode));
        //用头插法插入结点以建立链表
        p->adjvex=v2;
        p->next=g.vertices[v1].firstarc;
		p->info=info;
        g.vertices[v1].firstarc=p;
        e++;
        cin>>v1>>v2>>info;
    }
    g.vexnum=n;
    g.arcnum=e;
    return g;
}
void CountInDegree(AlGraph g,int *indegree)//取得图中各个顶点的入度
{
    for(int i=1;i<=g.vexnum;i++)
    {
        indegree[i]=0;
        for(int j=1;j<=g.vexnum;j++)//遍历图
        {
            ArcNode * p = g.vertices[j].firstarc;
            for(;p!=NULL;p=p->next)
            {
                int k = p->adjvex;
                if(g.vertices[k].vertex==g.vertices[i].vertex)indegree[i]++;
            }
        }
        //cout<<indegree[i]<<endl;
    }
}


//假设第 i 条弧为:< j, k >
//则第 i  项活动:
//“活动(弧)”的最早开始时间为:e(i)
//e(i)=ve(j)
//“活动(弧)”的最迟开始时间为:l(i)
//l(i)=vl(k)-dut(< j, k >)
//事件发生时间的计算公式:
//ve(源点)=0
//ve(k)=Max{ve(j)+dut(< j,k >) }
//vl(汇点)=ve(汇点)
//vl(j)=Min{ vl(k)-dut( <j,k >)} 

void TopologicalSort(AlGraph g,stack<vertype> &t)//拓扑排序算法
{
    int indegree[MAXNODE];//保存各个顶点的入度信息
    CountInDegree(g,indegree);//对各顶点求入度
    stack<vertype> s;
    for(int i=1;i<=g.vexnum;i++)
        if(!indegree[i])s.push(g.vertices[i].vertex);//入度为0者进栈
    int count=0;
	for(int j=1;j<=g.vexnum;j++)
	{
		ve[j]=0;
	}
    while(!s.empty())
    {
        vertype v = s.top();
        s.pop();
		t.push(v);//将拓扑排序逆序保存到t中
        //cout<<v<<" ";//输出顶点
        count++;
        for(ArcNode *p = g.vertices[v].firstarc;p!=NULL;p=p->next)
        {
            //对i号顶点的每个邻接点的入度减1,新产生的入度为0的顶点进栈
            int k = p->adjvex;
            if(!(--indegree[g.vertices[k].vertex]))s.push(g.vertices[k].vertex);
			if(ve[v]+p->info>ve[k])ve[k]=ve[v]+p->info;//求事件的最早发生时间
        }
    }
    if(count<g.vexnum)cout<<"图中存在回路"<<endl;
    else cout<<"存在拓扑序列"<<endl;
}

void CriticalPath(AlGraph g)//输出g的各项关键活动
{
	stack<vertype> t;
	TopologicalSort(g,t);
	for(int i=1;i<=g.vexnum;i++)
	{
		if(i==t.top())
		   vl[i]=ve[i];//初始化顶点事件的最迟发生事件
		else vl[i]=1000000;//无穷大
	}
	while(!t.empty())//求事件的最晚发生时间
	{
		vertype v = t.top();
        t.pop();
		//cout<<v<<" ";
		for(ArcNode *p = g.vertices[v].firstarc;p!=NULL;p=p->next)
		{
			int k=p->adjvex;
			int dut=p->info;
			if(vl[k]-dut<vl[v])vl[v]=vl[k]-dut;//取vl的最小值
		}
	}
	for(int p=1;p<=g.vexnum;p++)//输出事件最早最晚发生时间
	{
		cout<<p<<"  "<<"最早 "<<ve[p]<<"  最晚  "<<vl[p]<<endl;
	}
	for(int j=1;j<=g.vexnum;j++)//求e,l和关键活动
	{
		for(ArcNode *p = g.vertices[j].firstarc;p!=NULL;p=p->next)
		{
			int k=p->adjvex;
			int dut=p->info;
			e=ve[j];l=vl[k]-dut;
			int tag=(e==l)?1:0;
			cout<<j<<"->"<<k<<"  ";
			cout<<"活动最早开始时间: "<<e<<" ";
			cout<<"活动最晚开始时间: "<<l<<" ";
			if(tag)cout<<"关键路径"<<endl;
			else cout<<"不是关键路径"<<endl;
		}
	}
}
int main()
{
    AlGraph g;
    g=CreatAdjList(g);
    cout<<"图建立成功."<<endl;
    CriticalPath(g);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值