3.2.3 最短路径 Bellman-Ford算法

Bellman-Ford算法

Bellman-Ford算法的实现思路是通过不断迭代松弛操作来更新最短路径

松弛操作:不断更新最短路径和前驱结点的操作

三角形定理:两边之和大于第三边

任何图都满足三角形定理,因此可以求出最短的边

三角不等式是进行松弛操作的原理

dist[b]=min(dist[b],backup[a]+c);

适用情形:

  • 可以处理带有负权边的图
  • 实现通过m次迭代求出从起点到终点不超过m条边构成的最短路径。

算法实现

两层循环,内循环遍历所有边外循环迭代有限的次数

外循环迭代次数:迭代了k次,那么该距离更新的是从1号点经过不超过k条边到n号点的最短距离

在内循环中遍历了所有的边,但是需要控制有限的次数,所以每次只能更新走一条边到达的距离

例:先更新了2号点,又用2号点更新了3号点,发生串联,此时就不能保证走了多少次了

防止串联:更新时只用上一次循环的结果,因此需要将dist[]每次备份一遍

例题 AcWing853. 有边数限制的最短路

题目大意
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数

请你求出 1 号点经过最多 k 条边到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 impossible。

数据范围 1 ≤ n , k ≤ 500 1 ≤ m ≤ 10000 任意边长的绝对值不超过 10000 。

思路:

开结构体存边,bellman_ford算法求出k次限制内到达的最短路径

两重循环,外循环记录次数内循环遍历所有边

如果三角不等式成立更新最短距离

Solved:

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N=510,M=1e5+10,INF=0x3f3f3f3f;

int n,m,k;
int dist[N];//最短路径
int backup[N];//备份上次更新结果,防止走多

//存边,bellman_ford存边比较随意,只要可以遍历到即可
struct op
{
	int a,b,w;
}edge[M];
 
void bellman_ford()
{
	//初始化
	memset(dist,0x3f,sizeof(dist));
	dist[1]=0;

	for(int i=1;i<=k;i++){
		//每次循环只用上次循环结果
		memcpy(backup,dist,sizeof(dist));

		for(int j=1;j<=m;j++){
			int a=edge[j].a;
			int b=edge[j].b;
			int w=edge[j].w;

			//backup,防止多走一条边
			dist[b]=min(dist[b],backup[a]+w);
		}
	}

	//可能存在负权边,dist[N]更新时可能不==INF
	if(dist[n]>INF/2){
		cout<<"impossble"<<endl;
	}else{
		cout<<dist[n]<<endl;
	}
	return ;
}

signed main()
{
	cin>>n>>m>>k;
	for(int i=1;i<=m;i++){
		int a,b,w;cin>>a>>b>>w;
		edge[i]={a,b,w};
	}

	bellman_ford();
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值