《算法笔记》第4章 入门篇(2)---算法初步 10.7 关键路径

1.AOV网和AOE网

在这里插入图片描述
超级源点和超级汇点:

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

10.7.2 最长路径:

在这里插入图片描述

10.7.3 关键路径:

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

/*
    拓扑排序:
    1.设置栈 int类型 topOrder
    2.bool拓扑排序函数:
        1.设置队列q
        2.for循环,将所有入度为0的点放入到队列q中
        3.while循环:
            1.取出队首元素
            2.弹出
            3.将u加入到拓扑序列中
            4.for循环:
                1.取出当前u下的结点v
                2.对应的入度数--
                3.如果入度数为0,则入队
            5.用ve[u]来更新u的所有后继结点
        4.如果栈的长度为n,则返回true;否则返回false

*/

stack<int> topOrder;

bool tuopu()
{
    queue<int> q;
    for(int i=0; i<n; i++)
        if(inDegree[i]==0)
            q.push(i);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        topOrder.push(u);
        for(int i=0; i<G[u].size(); i++)
        {
            int v=G[u][i].v;      //G时数组结构
            inDegree(v)--;
            if(inDegree(v)==0)
                q.push(v);
        }    
        if(ve[u]+G[u][i].w>ve[v])
            ve[v]=ve[u]+G[u][i].w;
     
    }
    if(topOrder.size()==n)
        return true;
    else 
        return false;
}

在这里插入图片描述

/*
    1.对数组v1初始化,初始值为终点的ve值
    
    2.直接使用topOrder出栈即为你拓扑排序
    
    3.while循环:栈topOrder不为空
        1.设置u为栈顶元素
        2.弹出
        3.for循环
            1.找到G[u][i]的结点v
            2.用u的后继点v的vl来更新vl[u]


*/

fill(v1,v1+n,ve[n-1]);

while(!topOrder.empty())
{
    int u=topOrder.top();
    topOrder.pop();
    for(int i=0; i<G[u].size(); i++)
    {
        int v=G[u][i].v;
        if(vl[u]>vl[v]-G[u][i])
            vl[u]=vl[v]-G[u][i].w;
    }
}

在这里插入图片描述

/*

    e l分别表示活动ar最早开始时间和最晚开始时间
    ve vl分别表示最早发生时间和最晚发生时间
    
    e[r]=ve[i]
    
    vl[j]-length[r]=l[r]

    
    
    
    
    关键路径,不是有向无环图返回-1,否则返回关键路径长度
    
    int类型 CriticalPath()
    1.初始化ve数组的值为0
    2.如果不是有向无环图返回-1
    3.初始化vl数组,初始值为ve数组的最后一个值
    
    4.使用topOrder出栈
    1.while循环 topOrder不为空
    2.取出栈顶元素
    3.弹出
    4.for循环:
        1.遍历u的所有后继点
        2.设置int类型v为u的后继节点
        3.用u的所有后继节点v的vl值来更新vl[u]    为了找出vl[v]-G[u][i].w的最小值
        
    5.遍历邻接表的所有边,计算活动的最早开始时间e和最迟开始时间l
        1.双层for循环:
            1.分别取出v和w
            2.活动最早开始时间e为ve[u] 最晚开始时间 l为 vl[v]-w
            如果e为l
                输出关键活动
    6.返回关键路径长度:ve[n-1]


*/


int CriticalPath()
{
    memset(ve,0,sizeof(ve));
    if(tuopu()==false)
        return -1;
    fill(vl,vl+n,ve[n-1]);
    
    while(!topOrder.empty())
    {
        int u=topOrder.top();
        topOrder.pop();
        for(int i=0; i<G[u].size(); i++)
        {
            int v=G[u][i].v;
            if(vl[v]-G[u][i].w<vl[u])
                vl[u]=vl[v]-G[u][i].w;
        }
    }
    
    for(int u=0; u<n; u++)
        for(int i=0; i<G[u].size(); i++)
        {
            int v=G[u][i].v,w=G[u][i].w;
            int e=ve[u],l=vl[v]-w;
            if(e==l)
                printf("%d->%d",e,l);        
        }
        
    return ve[n-1];
}

在这里插入图片描述

int maxlength=0;

for(int i=0; i<n; i++)
{
    if(ve[i]>maxlength)
        maxlength=ve[i];
}

fill(ve,ve+n,maxlength);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值