[图算法]多段图最短路径

[图算法]多段图最短路径

多段图最短路径问题是应用动态规划的经典问题之一,许多优化问题都能转化为多段图最短路径问题进而求解。多段图最短路径的问题描述如下:

问题描述

设G=(V,E)是一个赋权有向图,其顶点集V被划分为k个不相交的子集Vi(1<=i<=k),其中,V1和Vk分别只有一个顶点s(称为源)和一个顶点t(称为汇),所有的边(u,v)的始点和终点都在相邻的两个子集Vi和Vi+1中, 且边(u,v)有一个正权重,记为w(u,v).请设计一个算法,求解从源s到汇t的权重之和最小的路径。

多段图最短路径示意图

问题分析

此问题具有最优子结构性质:假如1–2–7–10–12为上图中源节点1到汇节点12的一条最短路径,那么1–2–7–10一定为节点1到节点10的最短路径(反证法可以证明)。所以此问题适用于动态规划算法。
这里写图片描述

设w(i,p)为源节点s到节点v(i,p)的最短路径代价(i指阶段序号,p指第i阶段中的节点序号),而节点v(i+1,q)为节点v(i,p)的一个后继节点(所谓后继节点,即v(i+1,q)为v(i,p)下一阶段的一个节点,且v(i,p)到v(i+1,q)之间有一条路径。因为v(i,p)的后继节点可能有多个,所以设v(i+1,q)为“其中一个”后继节点。同理,称节点v(i,p)为节点v(i+1,q)的一个前驱结点)。则从源节点经由节点v(i,p)到节点v(i+1,q)的路径代价为w(i,p)+w(p,q)。当遍历v(i+1,q)的所有前驱节点后,会计算出一个最小的代价值,把它作为w(i+1,q)的值。把上述逻辑用数学递推式来表示为:
这里写图片描述

问题求解

采用自底向上的动态规划算法进行求解,先求解源s到第2阶段所有节点的最短路径,然后求第3阶段所有节点的最短路径,以此类推,直到求到汇节点t,即为我们所要求的值。程序中,我们采用一张表格(二维数组)来存储各个节点到源节点s的最短路径值。这样,我们能求出最短路径的值,如果还需要求具体的路径,则还需要维护一张表格,记录路径中的节点号。

以下程序摘自互联网资源 http://blog.csdn.net/u012432778/article/details/41623961 ,我没有亲自验证,不保证完全正确。

#include <stdio.h>
#include <stdlib.h>

#define MaxState 100

int minRoad[MaxState][MaxState];
void multiStageGraph(int stageNum, int *numPerStage);

int main()
{
    int i, k, ni[MaxState];
    while(scanf("%d", &k),k != -1)
    {
        for(i = 0; i < k; ++i)
        {
            scanf("%d", &ni[i]);
        }
        multiStageGraph(k, ni);
    }
    return 0;
}

void multiStageGraph(int stageNum, int *numPerStage)
{
    int i, q, p, weight, temp;
    memset(minRoad, 0x3f, sizeof(minRoad));           //初始化为一个充分大的数0x3f

    for (p = 0; p < numPerStage[0]; ++p)              //初始化源顶点层
    {
        minRoad[0][p] = 0;
    }

    for (i = 0; i < stageNum - 1; ++i)                //按段计算,终止与汇顶点的前一段
    {
        for (q = 0; q < numPerStage[i]; ++q)          //遍历第i段顶点
        {
            for (p = 0; p < numPerStage[i + 1]; ++p)  //遍历第i+1段顶点
            {
                scanf("%d", &weight);                 //读取边(q,p)的权重w(q,p)
                if (weight != -1)                     //存在边(q,p)
                {
                    temp = minRoad[i][q] + weight;
                    if (temp < minRoad[i+1][p])       //发现s到o的更短路径
                    {
                        minRoad[i+1][p] = temp;
                    }
                }
            }
        }
    }
    printf("%d\n", minRoad[stageNum-1][0]);
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

参考资料:
[1] http://blog.csdn.net/u012432778/article/details/41623961
[2] 算法导论第六部分:图算法

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值