算法设计作业:用动态规划求解多段图的最短路径问题

题目描述

对如下图所示的一个5段图,图上的数字代表该段路径的成本。写出求最短路径的计算过程,给出最短路径和距离。
在这里插入图片描述

思路分析

  1. 创建一个边权数组edgeWeigth,存储顶点和边的信息,用来表示图
  2. 创建一个cost数组,索引index代表顶点序号,cost[index]表示从起点1到达顶点index的最小路径和。cost实际上就是dp数组
  3. 状态转移方程:cost[index] = min{cost[指向index的顶点] + edgeWeigth[start][end]}start代表起点,end代表终点,要找到指向index的顶点,需要遍历边权数组。当index = 顶点总数N时,cost[N]就是我们要求的最短路径和
  4. dp的过程中,顺便用一个辅助数组path记录路径上的顶点

代码

#include <stdio.h>

#define INF 666 // infinity,定义无穷大
#define N 10  //顶点数

//vertex 0 is not used
int edgeWeight[N + 1][N + 1]; //边权数组
int path[N + 1] = {-1}; //路径数组

void CreateGraph(int vertexNum, int edgeNum);
int searchPath();
void printPath();

int main()
{
    // 读取顶点数和边数
    int vertexNum, edgeNum;
    scanf("%d%d", &vertexNum, &edgeNum);

    //创建边权图
    CreateGraph(vertexNum, edgeNum);

    printf("最短路径长度为:%d\n", searchPath());

    //输出最短路径
    printPath();

    return 0;
}

void CreateGraph(int vertexNum, int edgeNum)
{
    //初始化边的权值
    for (int i = 0; i <= vertexNum; i++)
        for (int j = 0; j <= vertexNum; j++)
            edgeWeight[i][j] = INF;

    //读取边的权值
    int weight;
    for (int i = 0; i < edgeNum; i++)
    {
        int v1, v2;
        scanf("%d%d%d", &v1, &v2, &weight);
        edgeWeight[v1][v2] = weight;
    }
}

// 求 N 个顶点的多段图的最短路径
int searchPath()
{
    int cost[N + 1]; //cost[index] 是到index顶点的已知最短路径的权值和
    cost[1] = 0;    //顶点1为起点
    for (int i = 2; i <= N; i++)
        cost[i] = INF;

    //v1 是起点,v2 是终点
    for (int v2 = 2; v2 <= N; v2++)
        for (int v1 = v2 - 1; v1 >= 1; v1--)
            //动态规划更新cost数组的信息
            if (cost[v1] + edgeWeight[v1][v2] < cost[v2])
            {
                cost[v2] = cost[v1] + edgeWeight[v1][v2];
                path[v2] = v1;  //表示最短路径中v2的前一个点是v1
            }

    return cost[N]; // 返回最短路径长度
}

//输出最短路径
void printPath()
{

    int positivePath[N + 1];    //正向路径
    positivePath[0] = N;    //终点顶点放在第一位
    int cnt = 1;    //记录路径中的顶点数

    //析取逆向路径
    int i = N;
    while (path[i] > 0)
    {
        positivePath[cnt++] = path[i];
        i = path[i];
    }

    //打印正向路径
    for (int i = cnt - 1; i > 0; i--)
        printf(" %d ->",positivePath[i]);

    printf(" %d",positivePath[0]);

}

测试输入

第一行:顶点数和边数
其余行:顶点标号 顶点标号 两顶点的边的权值
10 18
1 2 4
1 3 2
1 4 3
2 5 10
2 6 9
3 5 6
3 6 7
3 7 10
4 6 3
4 7 8
5 8 4
5 9 8
6 8 9
6 9 6
7 8 5
7 9 4
8 10 8
9 10 4

结果

在这里插入图片描述

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值