题目:一个美丽的小岛上有许多景点,景点之间有一条或者多条道路。现在进行自行车慢速比赛(最慢的选手获得冠军),工作人员在道路上标出自行车的单向行驶方向,所有比赛线路不会出现环,选手不能在中途的任何地方停下来,否则犯规,退出比赛。首先给定一行两个整数N和M,N为岛上的景点数(景点编号为0~N-1,N≤100),接下来的M行,每行为a、b、l,表示景点a和景点b之间的单向路径长度为L(L为整数)。最后一行为s和t,表示比赛的起点s和终点t。所有选手水平高超,都能够以自行车的最低速度行驶,并且所有自行车的最低速度相同。问冠军所走的路径长度是多少?假设只有一组测试数据。
输入:
7 10
1 2 5
1 5 6
1 6 8
2 3 7
2 6 4
3 6 5
4 5 9
4 7 5
5 6 3
6 7 2
1 5
输出:
6
思路:
典型最短路径算法,用于计算一个节点到其他节点的最短路径。这里可以考虑图算法—贝尔曼福特算法。
基本原理:逐遍的对图中每一个边去迭代计算起始点到其余各点的最短路径,执行N-1遍,最终得到起始点到其余各点的最短路径。(N为连通图结点数)
特点:贝尔曼福特算法是直接对所有边进行N-1遍松弛操作。
贝尔曼福特算法边的权值可以为负数,并可检测负权回路。
名词解释:
1. 松弛操作:不断更新最短路径和前驱结点的操作。
2. 负权回路:绕一圈绕回来发现到自己的距离从0变成了负数,到各结点的距离无限制的降低,停不下来。参考:算法系列——贝尔曼福特算法(Bellman-Ford)_lzh1366的博客-CSDN博客
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define INF 0x3f3f3f3f //定义∞
#define MAXV 101
int A[MAXV][MAXV]; //邻接矩阵
int n, m;
int s, t;
int dist[MAXV];
void BellmanFord(int v) //贝尔曼-福特算法
{
int i, k, u;
for (i = 0; i < n; i++)
dist[i] = A[v][i]; //对dist0[i]初始化
for (k = 1; k < n; k++) //从dist0[u]递推出dist2[u], …,distn-1[u]循环n-2次
{
for (u = 0; u < n; u++) //修改所有非顶点v的dist[]值
{
if (u != v)
{
for (i = 0; i < n; i++)
{
if (A[i][u]<INF && dist[u]>dist[i] + A[i][u])
dist[u] = dist[i] + A[i][u];
}
}
}
}
}
int main()
{
int i, j;
int a, b, l;
scanf("%d%d", &n, &m); //输入n、m
for (i = 0; i < n; i++) //初始化邻接矩阵
for (j = 0; j < n; j++)
if (i == j)
A[i][j] = 0;
else
A[i][j] = INF;
for (i = 0; i < m; i++) //输入边
{
scanf("%d%d%d", &a, &b, &l);
A[a][b] = -l;
}
scanf("%d%d", &s, &t); //输入s和t
BellmanFord(s); //采用BellmanFord算法求s出发的最短路径
printf("%d\n", -dist[t]); //输出结果
return 1;
}
结果: