AOE 关键路径

http://blog.csdn.net/kay_sprint/article/details/6696701

以边表示活动,以顶点表示事件的有向网称为AOE(activity on edge)网.AOE网是一个
有向无环图,权值表示活动持续的时间。可以用AOE网来估计工程完成的时间。由于工程
只有一个开始点和一个完成点,所以在无环路的条件下,网中只有一个入度为0的点和一
个出度为0的点.
下面是几个和AOE网有关的概念:
(1)路径长度:路径上各个活动的持续时间之和

(2)完成工程的最短时间:由于AOE网中有活动是并行进行的,所以完成工程的最短时间
就是从开始点到完成点的最长路劲长度。
(3)活动最早开始时间(earlist time)(e(i)):从开始点到顶点vi的最长路径称为事件vi的最早发生时间,

这个时间决定了以vi为尾的弧表示的活动的最早开始时间.
(4)活动最晚开始时间(latest time)(l(i)):在不推迟整个工程完成的前提下,活动最迟开始的时间
(5)完成活动的时间余量:该活动的最迟开始时间减去最早开始时间
(6)关键路径(critical path):路径长度最长的路径称为关键路径
(7)关键活动(critical activity):关键路径上的活动称为关键活动,关键活动的特点是:e(i)=l(i)
分析关键路径的目的就是辨别在整个工程中哪些是关键活动,以便争取提高关键活动的工作
效率,缩短整个工程的工期。


#include<iostream>  
#include<string>  
#include<stack>  
#include<iomanip>  
using namespace std;  
  
const int MAX_VEX_NUM=20;  
int ve[20];//全局变量,存放各个事件的最早发生时间  
  
class ArcNode //表结点  
{  
public:  
    int adjvex;  
    int info;//权值  
    ArcNode *nextarc;  
};  
  
class VNode //头结点  
{  
public:  
    string data;  
    int indegree; //顶点的入度  
    ArcNode *firstarc;  
};  
  
class ALGraph   
{  
private:  
    VNode vertices[MAX_VEX_NUM];  
    int arcnum;  
    int vexnum;  
public:  
  
    void Create_ALG()  
    {  
        //构造有向网       
        string v1,v2;  
        int i,j,w;  
        ArcNode *p=NULL;  
  
        cout<<"输入顶点数和边数:";  
        cin>>vexnum>>arcnum;  
  
        cout<<"输入顶点名称:";  
        for(i=0;i<vexnum;i++)  
        {  
            cin>>vertices[i].data;  
            vertices[i].firstarc=NULL;  
            vertices[i].indegree=0;  
        }  
  
        for(int k=0;k<arcnum;k++)  
        {  
            cout<<"按照尾->头的顺序输入每条边对应的两个顶点和该边的权值:";  
            cin>>v1>>v2>>w;  
            i=Locate_Vex(v1);  
            j=Locate_Vex(v2);  
  
            while(i==-1 || j==-1)  
            {  
                cout<<"输入的顶点错误,重新输入:";  
                cin>>v1>>v2;  
                i=Locate_Vex(v1);  
                j=Locate_Vex(v2);  
            }  
  
            p=new ArcNode;  
            p->adjvex=j;  
            p->info=w;  
            p->nextarc=vertices[i].firstarc;  
            vertices[i].firstarc=p;  
            vertices[j].indegree+=1; //作为有向弧的头的顶点入度加1  
        }  
  
        cout<<"有向网构造完成"<<endl;  
    }  
  
    int Locate_Vex(string v) //求顶点在顶点数组中的位置  
    {  
        for(int k=0;k<vexnum && vertices[k].data!=v;k++);  
        if(k<vexnum)  
            return k;  
        else  
            return -1;  
    }  
                                /*关键路径求解思想*/  
            /*--------------------------------------------------------------- 
            / 辨别关键路径就是要找出l(i)=e(i)的活动,为了求AOE网中的e(i)和l(i) 
            / 首先应该求出每个事件的最早发生时间ve(j)和最晚发生时间vl(j),如果 
            / 活动ai用弧<j,k>表示,那么持续时间记为dut(<j,k>).则有如下关系: 
            / e(i)=ve(j),   l(i)=vl(k)-dut(<j,k>); 
            / 求事件的vj的最早发生时间ve(j)和最迟发生时间vl(j)要分两步进行: 
            / (1):从ve(0)=0(假设顶点0是开始点)开始,根据下面公式计算其它事件 
            / 的最早开始时间: ve(j)=Max{ve(i)+dut(<i,j>)} 其中i是j的所有直接前驱的集合 
            / (2)从vl(n-1)=ve(n-1)开始,根据下面公式计算其他事件的最晚开始时间: 
            / vl(i)=Min{vl(j)-dut(<i,j>)} 其中j是i的直接后继的集合 
            / 上述两个公式必须分别在拓扑有序和逆拓扑有序的前提下进行,也就是说ve(j-1) 
            / 必须在vj全部直接前驱的最早发生时间都求得以后才能确定。而vl(j-1)则必须在 
            / vj的所有直接后继的最晚发生时间求得之后才能确定,因此可以在拓扑排序的基础 
            / 上计算所有事件的ve(j-1)和vl(j-1). 
            / 为了能按逆拓扑有序序列的顺序计算各个顶点的vl值,需记下在拓扑排序的过程中 
            / 求得的拓扑有序序列,这只需要增加多一个栈,用来存储拓扑有序序列即可. 
            / 由于栈的结构特点,拓扑有序序列出栈就变成逆拓扑有序序列了. 
            /----------------------------------------------------------------*/  
  
    //求所有事件的最早发生时间  
    bool Topo_Order(stack<int> &T)  
    {  
        stack<int> s;  
        ArcNode *p=NULL;  
        for(int i=0;i<vexnum;i++)  
            if(!vertices[i].indegree)  
                s.push(i);  
        int count=0;  
        for(i=0;i<vexnum;i++)  
            ve[i]=0; //设各顶点最早发生为0  
        while(!s.empty())  
        {  
            int k=s.top();  
            s.pop();  
            T.push(k);  
            count++;  
            for(p=vertices[k].firstarc;p;p=p->nextarc)  
            {  
                int w=p->adjvex;  
                if(vertices[w].indegree)  
                    vertices[w].indegree--;  
                if(!vertices[w].indegree)  
                    s.push(w);  
                if(ve[k]+p->info>ve[w]) //求ve[w]的最早发生时间  
                    ve[w]=ve[k]+p->info;  
            }  
        }  
        if(count<vexnum)  
            return 0;  
        else  
            return 1;  
    }  
      
    //求所有事件的最晚发生时间并求出关键活动和关键路径  
    void Critical_Path()  
    {  
        stack<int> T;  
        string cp[10];  
        int c=0;  
        if(!Topo_Order(T))  
        {  
            cout<<"该有向网有环!"<<endl;  
            return;  
        }  
        int vl[20];  
        for(int i=0;i<vexnum;i++)  
            vl[i]=ve[vexnum-1]; //初始化顶点事件最迟发生时间, 将所有点的最迟发生时间都设为ve[vexnum-1]
  
          
        while(!T.empty())  
        {  
            ArcNode *p=NULL;  
            int j=T.top();  
            T.pop();  
            for(p=vertices[j].firstarc;p;p=p->nextarc)  
            {  
                int k=p->adjvex;  
                int dut=p->info;  
                if(vl[k]-dut<vl[j])  
                    vl[j]=vl[k]-dut;  
            }  
        }  
        //下面是根据关键活动的特点(最早开始时间和最晚开始时间相等)求关键活动,做上标记  
        cout<<"tail  head  weight  earliest time  latest time  tag "<<endl;  
        for(int j=0;j<vexnum;j++)  
            for(ArcNode *p=vertices[j].firstarc;p;p=p->nextarc)  
            {  
                int k=p->adjvex;  
                int dut=p->info;  
                int ee=ve[j];  
                int el=vl[k]-dut;  
                char tag;  
                tag=(ee==el)?'*':' ';  
                cout<<setw(3)<<vertices[j].data<<setw(6)<<vertices[k].data<<setw(7)<<dut<<setw(9)<<ee<<setw(16)<<el<<setw(9)<<tag<<endl;  
                if(tag=='*' && j==0)  
                {  
                    cp[c]=vertices[j].data;  
                    c++;  
                    cp[c]=vertices[k].data;  
                    c++;  
                }  
                else if(tag=='*' && j!=0)  
                {  
                    cp[c]=vertices[k].data;  
                    c++;  
                }             
            }  
        cout<<"The critical activities are ended with * "<<endl;  
        cout<<"So the critical path is :";  
        for(i=0;i<c-1;i++)  
            cout<<cp[i]<<"->";  
        cout<<cp[c-1]<<endl;  
    }  
  
};  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值