题目描述
对如下图所示的一个5段图,图上的数字代表该段路径的成本。写出求最短路径的计算过程,给出最短路径和距离。
思路分析
- 创建一个边权数组
edgeWeigth
,存储顶点和边的信息,用来表示图 - 创建一个
cost
数组,索引index
代表顶点序号,cost[index]
表示从起点1到达顶点index
的最小路径和。cost
实际上就是dp
数组 - 状态转移方程:
cost[index] = min{cost[指向index的顶点] + edgeWeigth[start][end]}
。start
代表起点,end
代表终点,要找到指向index的顶点
,需要遍历边权数组。当index = 顶点总数N
时,cost[N]
就是我们要求的最短路径和 - 在
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