题目描述
对如下图所示的一个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