bellman_ford算法:有边数限制的最短路,可以处理重边、负边和自环。
给定一个n个点m条边的有向图,图中可能存在重边和自环, 边权可能为负数。
请你求出从1号点到n号点的最多经过k条边的最短距离,如果无法从1号点走到n号点,输出impossible。
注意:图中可能 存在负权回路 。
输入格式
第一行包含三个整数n,m,k。
接下来m行,每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。
输出格式
输出一个整数,表示从1号点到n号点的最多经过k条边的最短距离。
如果不存在满足条件的路径,则输出“impossible”。
数据范围
1≤n,k≤500,
1≤m≤10000,
任意边长的绝对值不超过10000。
输入样例:
3 3 1
1 2 1
2 3 1
1 3 3
输出样例:
3
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 510, M = 10001; int d[N], backup[N]; int n, m, k; struct edges{ int a, b, w; }Edge[M]; int bellman_ford() { memset(d, 0x3f, sizeof d); d[1] = 0; for(int i = 0;i<k;i++) { memcpy(backup, d, sizeof d); for(int j = 0;j < m;j++)//注意这里是要循环结束到m,因为输入的边数就是m。 { int a = Edge[j].a, b = Edge[j].b, w = Edge[j].w; d[b] = min(d[b], backup[a] + w); } } if(d[n] > 0x3f3f3f3f / 2) return -1; return d[n]; } int main() { cin>>n>>m>>k; for(int i = 0;i<m;i++) { int a, b, w; cin>>a>>b>>w; Edge[i] = {a,b,w}; } int t = bellman_ford(); if(t == -1) cout<<"impossible"<<endl; else cout<<t<<endl; }
限制多少边就循环多少次,放进备份数组里面是为了防止本次循环就发生串联,等到k下一次循环的时候再用重新复制过的备份数组,这样就可以在之前的基础上继续前进 而不会 超出k条边的限制了。
第一次只会更新从起点出发一条边能到达的地方,下一次就更新第二条能到达的,以此递增类推。
k = 1, d[1] = 0, d[2] = 1, d[3] = 3, 这里d[3]不会更新为d[2] + 1,因为用的是上次备份的d[2] +oo
k = 2, d[1] = 0, d[2] = 1, d[3] = min(3, 1 + 1) = 2;
for n 次
for所有边a, b, w
dist[b] = min(dist[b], dist[a] + w); //每次无脑的对所有的边进行松弛操作。