写在所有的前面:
本文采用C++实现代码
目录
题目说明
题目:最短路径
题目出处
广西大学oj
22级《算法设计与分析》第三次课堂作业
链接:https://oj.gxu.edu.cn/contest/626/problem/0003
题目描述Description
给出一个有向图(无负权值),求任意两点间的最短路径
输入Input
第一行为有向图中点的数量n(各点从0到n-1编号)
第二行为边的数量 m
第三行为要求其间最短路径的两个点
第四行起为m条边的信息,包括起点、终点和路径长度(保证长度是整数,且绝对值不大于100)
以空格隔开
输出Output
求出输入中第三行两个点之间的最短路径长度并输出
样例Sample
输入
8
15
0 5
4 5 35
5 4 35
4 7 37
5 7 28
7 5 28
5 1 32
0 4 38
0 2 26
7 3 39
1 3 29
2 7 34
6 2 40
3 6 52
6 0 58
6 4 93
输出
73
限制Hint
保证n小于1000,且答案不超过 10^5.
解答说明
方案1:Dijkstra算法
解题思路
一般情况
- 遍历边,寻找最小费用结点(不在路径内)
- 将最小结点加入最短路径
- 更新其带来的改变(相邻点最小费用记录)
特殊情况
- 初始化:总起点作为路径起点并更新最小费用记录
- 未找到可用结点(无法生成最短路径)
代码实现
#include<iostream>
using namespace std;
//Dijkstra最短路径算法
const int N = 1010, MAXVALUE = 1e5 + 10;
int n, m, a, b;// 结点数,边数,总起点,总终点
int w[N][3];// 边 w[i][0] 费用,w[i][1] 起点,w[i][2] 终点
int min1[N][2];// min[i][0] 结点 a 到 i 最小费用,min[i][1] 结点是否已被计算入最短路径 是 1 / 否 0
int main()
{
scanf("%d", &n);
scanf("%d", &m);
scanf("%d%d", &a, &b);
//题目要求 i 从 0 开始,共 n 个结点
for (int i = 0; i < n; i++) min1[i][0] = MAXVALUE;//结点 a 到 i 最小费用初始化为无穷大
//输入边
for (int i = 0; i < m; i++)
{
scanf("%d%d%d", &w[i][1], &w[i][2], &w[i][0]);
}
//最短路径寻找
//将 a 结点作为路径起点
min1[a][0] = 0, min1[a][1] = 1;
//更新 min
for (int i = 0; i < m; i++)//每一条边
{
if (w[i][1] == a)// a 结点作为边的起点
min1[w[i][2]][0] = w[i][0];// 将该边费用定为 a 到该边终点 w[i][2] 结点的最小费用
}
//插入其他结点
for (int i = 0; i < n - 1; i++)//最多选择 n - 1 次结点
{
//寻找最小费用结点
int p = -1, pmin = MAXVALUE;//最小费用边指针,最小费用
for (int j = 0; j < m; j++)//遍历每一条边
{
if (min1[w[j][2]][0] < pmin && min1[w[j][2]][1] == 0)// a 到该边终点费用更小 且 终点不在路径内
{
p = j;//更新最小费用边指针
pmin = min1[w[j][2]][0];//更新最小费用
}
}
//未找到可用结点,即无法生成最短路径
if (pmin == MAXVALUE)
{
printf("Imp");
return 0;
}
// b 结点为最小结点
if (w[p][2] == b)
{
printf("%d", pmin);
return 0;
}
//将最小结点加入最短路径
min1[w[p][2]][1] = 1;
//更新 min
for (int j = 0; j < m; j++)//每一条边
{
if (w[j][1] == w[p][2] && pmin + w[j][0] < min1[w[j][2]][0])// 边的起点为所求最小结点 且 起点最小费用 + 边费用 小于 终点的最小费用
min1[w[j][2]][0] = pmin + w[j][0];// 更新终点 w[i][2] 结点的最小费用
}
}
return 0;
}
其他解释
floyd 算法待写