图的应用之关键路径

快一个月没更了,我好懒!!!

简要介绍

AOE网

若在带权的有向图中,以顶点表示事件,以有向边表示活动,边上的权值表示活动的开销(如该活动持续的时间),则此带权的有向图称为AOE网。

关键路径

如果用AOE网来表示一项工程,那么,仅仅考虑各个子工程之间的优先关系还不够,更多的是关心整个工程完成的最短时间是多少;哪些活动的延期将会影响整个工程的进度,而加速这些活动是否会提高整个工程的效率。这些活动(边)就叫关键路径。

题目介绍

输入形式:第一行输入两个数字,分别表示顶点数和边数;从第二行开始,输入边的信息,格式为(i,j, weight)
输出形式:关键路径的总时间(最大路径长度),代表关键活动的边,格式为(顶点1,顶点2),按大小顺序排列

【样例输入】
6 8
0 1 3
0 2 2
1 3 2
1 4 3
2 3 4
2 5 3
3 5 2
4 5 1
【样例输出】
8
0 2
2 3
3 5

算法思想

要求解关键路径我们得先了解四个重要概念:

事件最早发生时间(ETV)

顾名思义,事件最早发生时间就是顶点的最早发生时间,对0而言,其ETV自然是0,对1而言它的ETV就是其前驱事件的最早发生时间加上其活动的持续时间(a1),对3而言,其前驱事件有多个,就取最晚发生的那一个(ETV2+a5),其它的依次类推就好了

事件最晚发生事件(LTV)

就是最迟该事件需要开始的时间,不然就会延误时间。所以不难想到,LTV5=ETV5,对每个节点,其LTV就是其后继事件的最晚发生时间减去其活动持续时间,和ETV类似就不多赘述。

活动的最早开工时间(ETE)

显然,活动的最早开工时间就是活动发生前的事件的最早开始时间

活动的最晚开工时间(LTE)

活动的最晚开工时间,就是最迟该活动需要开始的时间,不然就会延误时间。如LTE3=LTV-a7。

知道ETV和LTV就可以求ETE和LTE,再次强调关键路径是活动的集合,所以得求ETE和LTE,

ETV和LTE相等的活动就是关键活动。

代码实现

#include <iostream>
#define maxsize 100
#include <stack>
using namespace std;
int like[maxsize]={0};
int flag=0;
int i,number=0,k,f=0;
int E[maxsize]={0},L[maxsize];
int pathe[maxsize][maxsize]={0};
int pathl[maxsize][maxsize]={0};
int keypoint[maxsize]={0};
stack <int>pathlike1;
stack <int>pathlike2;
stack <int>s;
struct ArcNode
{
    int adjvex,weight;
    ArcNode *nextarc=NULL;
};
struct VertexNode
{
    int date,in,out,flag2;
    ArcNode *firstarc;
};
struct AdjList
{
    VertexNode vertex[maxsize];
    int vexnum,arcnum;
};
void CreatGraph(AdjList *a)
{
    int x,y,z;
    for(int i=0;i<a->vexnum;i++)
    {
        a->vertex[i].date=i;
        a->vertex[i].in=0;
        a->vertex[i].out=0;
        a->vertex[i].firstarc=NULL;
        a->vertex[i].flag2=0;
    }
     for(int j=0;j<a->arcnum;j++)
    {
            cin>>x>>y>>z;
            pathe[x][y]=z;
            pathl[y][x]=z;
            int flag1=0;
            ArcNode *p=new ArcNode;
            ArcNode *q=a->vertex[x].firstarc;
            if(q)
            {
                flag1=1;
                while(q->nextarc)
                q=q->nextarc;
            }
            if(flag1)
            q->nextarc=p;
            else
            a->vertex[x].firstarc=p;
            p->adjvex=y;
            p->weight=z;
            a->vertex[x].out++;
            a->vertex[y].in++;
    }
    for(i=0;i<a->vexnum;i++)
    if(!a->vertex[i].in)
        s.push(i),a->vertex[i].flag2=1;
}
void likeya (AdjList *a)
{
     ArcNode *p;
     while(!s.empty())
    {
        i=s.top();
        s.pop();
        like[flag++]=i;
        number++;
        p=a->vertex[i].firstarc;
        while(p)
       {
            k=p->adjvex;
            a->vertex[k].in--;
            p=p->nextarc;
       }
    }
    for(i=0;i<a->vexnum;i++)
    if(a->vertex[i].in==0&&a->vertex[i].flag2==0)
        s.push(i),a->vertex[i].flag2=1;
    if(!s.empty())
    likeya(a);
}
int topulike(AdjList *a)
{
    likeya(a);
    if(number<a->vexnum)
        return 0;
    else
        return 1;
}
void gete()
{
    E[0]=0;
    for(i=1;i<flag;i++)
    for(int j=0;j<flag;j++)
    {
        if(pathe[j][i]&&pathe[j][i]+E[j]>E[i])
         E[i]=E[j]+pathe[j][i];
    }
   /* for(int j=0;j<flag;j++)
        cout<<E[j]<<" ";
    cout<<endl;*/
}
void getl()
{
    for(int j=0;j<flag;j++)
    L[j]=8888888;
    L[flag-1]=E[flag-1];
    for(i=flag-1;i>=1;i--)
    for(int j=flag-2;j>=0;j--)
    {
        if(pathl[i][j]&&L[i]-pathl[i][j]<L[j])
            L[j]=L[i]-pathl[i][j];

    }
    /*for(int j=0;j<flag;j++)
    cout<<L[j]<<" ";
    cout<<endl;*/
}
void likeend(AdjList *a)
{
    int g,ete,lte;
    ArcNode *e;
    cout<<E[flag-1]<<endl;
    for(int j=0;j<a->vexnum;j++)
    {
        for(e=a->vertex[j].firstarc;e;e=e->nextarc)
        {
            g=e->adjvex;
            ete=E[j];
            lte=L[g]-e->weight;
            if(ete==lte)
            cout<<a->vertex[j].date<<" "<<a->vertex[g].date<<endl;
        }
    }

}
int main()
{
    AdjList a;
    cin>>a.vexnum>>a.arcnum;
    CreatGraph(&a);
    if(topulike(&a))
    gete();
    getl();
    likeend(&a);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LIKE呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值