往期博文:
Bellman_ford 算法--带负权值的单源最短路问题,边列表存储-优快云博客
这三道题目都是关于bellman_ford求最短路的问题,只是条件不同,这是最后一期,建议大家三期一期学习哦👍👍👍
一、题目描述
二、解题思路
最多经过 k 个城市的条件下,而不是一定经过k个城市,也可以经过的城市数量比k小,但要最短的路径。
在 kama94.城市间货物运输I 中我们讲了:对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离。节点数量为n,起点到终点,最多是 n-1 条边相连。 那么对所有边松弛 n-1 次 就一定能得到 起点到达 终点的最短距离。
本题是最多经过 k 个城市, 那么是 k + 1条边相连的节点。 所以本题就是求:起点最多经过k + 1 条边到达终点的最短距离。
对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离,那么对所有边松弛 k + 1次,就是求 起点到达 与起点k + 1条边相连的节点的 最短距离。
但是这样就造成了一个情况,即:计算minDist数组的时候,基于了本次松弛的 minDist数值,而不是上一次 松弛时候minDist的数值。所以在每次计算 minDist 时候,要基于 对所有边上一次松弛的 minDist 数值才行,所以我们要记录上一次松弛的minDist。😢😢😢😢😢
why?
在对所有边松弛第一次的过程中,大家会发现,不仅仅 与起点一条边相连的节点更新了,所有节点都更新了。
而且对所有边的后面几次松弛,同样是更新了所有的节点,说明 至多经过k 个节点 这个限制 根本没有限制住,每个节点的数值都被更新了。 代码随想录 ---可以看看卡哥是怎么讲解的呜呜呜
三、完整代码
//对所有边松弛k+1次
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
vector<vector<int>> edges;
for(int i=1;i<=m;i++)
{
int s,t,v;
cin>>s>>t>>v;
edges.push_back({s,t,v});
}
int src,dst,k;
cin>>src>>dst>>k;
int start=src;
int end=dst;
//初始化距离数组
vector<int> mindist(n+1,INT_MAX);
// 用来记录上一次遍历的结果
vector<int> mindist_copy(n + 1);
mindist[start]=0;
//对每条边进行k+1次松弛
for(int i=1;i<=k+1;i++)
{
mindist_copy = mindist; // 获取上一次计算的结果
for(auto edge:edges)
{
int from=edge[0];
int to=edge[1];
int cost=edge[2];
// 注意使用 minDist_copy 来计算更新 新的minDist[to]
if(mindist_copy[from]!=INT_MAX)
{
mindist[to]=min(mindist[to],mindist_copy[from]+cost);
}
}
}
if(mindist[end]==INT_MAX) cout<<"unreachable";
else cout<<mindist[end];
return 0;
}
四、总结
auv,现在我刚学玩这个系列,真的感觉很熟悉很熟悉了,代码写了五六七八遍了,但是我相信自己下次碰到类似的新题,,,,,肯定不能一鼓作气写出来代码。。。。Bellman-Ford的核心优势是能够处理图中存在负权边的情况,但是即使图中所有边权均为非负值,Bellman-Ford算法仍然能正确计算最短路径,只是效率不如Dijkstra算法【看下面的博客,说实话我已经忘了他是怎么更新 的了.......😭😭😭😭】