⬅ 返回

1、思路

解决图中可能存在重边和自环, 边权可能为负数。并且有边数限制的最短路只能用bellman_ford

📌

0.初始化dist数组为正无穷,dist[1]=0; 1.(外重循环)循环i从1到n,遍历n次指的:是不经过i条边到达终点的最短距离

经过n次操作n个点的最短距离也就确定了;

2.(内重循环)循环j从1到m,遍历m条边,把所有边都进行松弛操作;

每次取出两点以及他们连接的边的权重(a,b,w表示a—>b的一条边);

用从起点到a的当前最短距离+权重来更新从起点到b的当前最短距离; dist[b]=min(dist[b],dist[a]+w);

3.返回答案;

2、所用的数据结构和方法

📌

dist[N]表示从起点到当前点的当前最短距离 backup[j]表示每次进入第2重循环的dist数组的备份

//用结构体来储存所有边

//备份 防止dist修改影响遍历

memcpy(backup, dist, sizeof dist);

3、代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#define PI 3.14159
using namespace std;
 
typedef pair<int,int> PII;
typedef long long LL;
const int MAX_INT =  0x3f3f3f3f;
const int N = 1e5+15;
const int mod = 1e9+7;
//用结构体来储存所有边
int n,m,k;
struct Edge{
	int a;
	int b;//表示a-b 之间有一条边 权值为c
	int c;
};
Edge e[N];
int dist[N],backup[N];
 
 
void solve()
{
	cin>>n>>m>>k;
	for(int i=1;i<=m;i++)
	{
		cin>>e[i].a>>e[i].b>>e[i].c;
	}
	memset(dist,0x3f,sizeof dist);
	
	dist[1]=0;//不要忘了让第一个点的距离为0
	for(int i=1;i<=k;i++)//遍历k次 k为边数限制 遍历k次不要求i从1开始
	{
		memcpy(backup,dist,sizeof dist);//备份 防止dist修改影响遍历
		for(int j=1;j<=m;j++)
		{
			int a = e[j].a;
			int b = e[j].b;
			int c = e[j].c;
			dist[b] = min(dist[b],backup[a]+c);//用备份的路径修改dist 或者说用上一次遍历的结果增加一条边
		}
	}
	if(dist[n]>=MAX_INT/2)
		cout<<"impossible"<<endl;// >的原因是因为存在负值 可能存在比无穷大 小1的情况 不能用等号
	else
		cout<<dist[n]<<endl;
	
	
 
}
 
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 
    int T = 1;
    while(T--)
    {
        solve();
    }
}

4、例题

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

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

注意:图中可能 存在负权回路