用处:
1.解决存在负权边的最短路问题。
2.解决有边数限制的最短路问题。(此算法特有)
算法模板
memset(dis, 0x3f, sizeof dis); dis[1] = 0;
for (int i = 0; i < k; i++) // 遍历边数
{
memcpy(backup, dis, sizeof dis); // 将上一条边的dis拷贝到backup
for (int j = 0; j < m; j++)
{
int x = e[j].x, y = e[j].y, w = e[j].w;
dis[y] = min(dis[y], backup[x] + w); // 取1到y的最短路径
}
}
例:
1到2的距离为1
2到3的距离为1
1到3的距离为3
该算法每一轮会遍历所有边但每一轮只更新一条路径的一个边。
这也是为什么这个算法可以解决有边数限制的最短路问题。
第一轮
1到2的最短距离为1
1到3的最短距离为3第二轮
1到2的距离为1
1到3的距离为2 (1到2 ,2到3)
反过来再看模板
更新最短路径
w//为一条边的权值
dis[y] = min(dis[y], backup[x] + w); // 取1到y的最短路径
注意这里有个backup
数组,这个是什么?
想一想如果将代码写成这样dis[y] = min(dis[y], dis[x] + w);
会发生什么?
注意一下算法原理:每一轮会遍历所有边但每一轮只更新一条路径的一个边。
每一轮会遍历所有边,如果是这么写
dis[y] = min(dis[y], dis[x] + w);
。
拿上面例子举例:(距离初始化为无穷)
第一轮更新1到2的最短距离的d[2]
此时d[2]
不为无穷。
遍历所有边,当遍历到2到3时此时,d[2]
不为无穷,d[3] = d[2] + w
(初始化时d[3] 无穷)
这一轮更新了一条路径的两条边,这就违背了算法原理:每一轮只更新一条路径的一个边。
backup数组为上一轮dis数组的值。
第一轮dis更新,不会涉及到backup数组。
第一轮后d[2] = 1
,d[3] = 3
;此时第二轮backup
数组的值为backup[2] = 1
,backup[3] = 3
。
第二轮看代码dis[y] = min(dis[y], backup[x] + w);
更新1到3的最短路dis[3] = backup[2] + 1 = 3;
(2到3的权值w=1)