bellman_ford算法
1)初始化所有点到源点的距离为∞,把源点到自己的距离设置为0;
2)不管3721遍历n次;每次遍历m条边,用每一条边去更新各点到源点的距离。
值得注意的是
1) 需要把dist数组进行一个备份,这样防止每次更新的时候出现串联;
2) 由于存在负权边,因此return -1的条件就要改成dist[n]>0x3f3f3f3f/2;
3) 上面所谓的n次遍历的实际含义是当前的最短路径最多有n-1条边,这也就解释了为啥要i遍历到n的时候退出循环了,因为只有n个点,最短路径无环最多就存在n-1条边。
4) 这里无需对重边和自环做单独的处理:
1] 重边:由于遍历了所有的边,总会遍历到较短的那一条;
2] 自环: 有自环就有自环啊,反正又不会死循环;
5) 令人愉悦的是,该算法无非就是循环n次然后遍历所有的边,因此不需要做什么特别的存储,只要把所有的边的信息存下来能够遍历就行;
6)bellman_ford算法可以存在负权回路,因为它求得的最短路是有限制的,是限制了边数的,这样不会永久的走下去,会得到一个解;
7)SPFA算法各方面优于该算法,但是在碰到限制了最短路径上边的长度时就只能用bellman_ford了,此时直接把n重循环改成k次循环即可
代码
#include<iostream>
#include<cstring>
using namespace std;
const int N=510,M=10010;
struct Edge{
int a;
int b;
int w;
}e[M];//把每个边保存下来即可
int dist[N];
int back[N];//备份数组放置串联
int n,m,k;//k代表最短路径最多包涵k条边
int bellman_ford(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
for(int i=0;i<k;i++){//k次循环
memcpy(back,dist,sizeof dist);
for(int j=0;j<m;j++){//遍历所有边
int a=e[j].a,b=e[j].b,w=e[j].w;
dist[b]=min(dist[b],back[a]+w);//使用backup:避免给a更新后立马更新b,这样b一次性最短路径就多了两条边出来
}
}
if(dist[n]>0x3f3f3f3f/2) return -1;
else return dist[n];
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<m;i++){
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
e[i]={a,b,w};
}
int res=bellman_ford();
if(res==-1) puts("impossible");
else cout<<res;
return 0;
}
加强的那一个数据怎么才能过
y总代码已经更新了
就一个数据,dist[n]==-1的时候,直接在函数里面输出,靠返回值返回的话会出问题
if (dist[n] > 0x3f3f3f3f / 2) return -1;
这里为什么是判断dist[n]>0x3f3f3f3f/2啊
作者:松鼠爱葡萄
链接:https://www.acwing.com/solution/content/14088/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
为什么你的代码和松鼠爱吃葡萄一样
好像过不去了
数据加强了
我弱弱的问一下,贝尔曼福特到底是限制了边的数量还是边的长度啊?我记得是限制了边的数量啊,大佬是不是写错了?
如果没有边数限制的话 是不用备份的
也还是要备份的
不对吧,没有边数限制,应该不需要备份了把?求老哥解释解释
不用备份
不需要
“n次遍历的实际含义是当前的最短路径最多有n-1条边” 这句话有误吧,应该是n-1次遍历
Or2
tql
其实对于第7点求有边数限制的最短路依然可以用队列优化的Bellman Ford算法,不过流程和SPFA稍有不同,我们需要在拓展时分层拓展,并且在入队判重的时候只判断下一层的节点。
%%%