dijstra算法基于贪心思想,当有负权边时,局部最优不一定是全局最优,所以采用bellman - ford算法
Bellman - ford 算法是求含负权图的单源最短路径的一种算法,效率较低,代码难度较小。其原理为连续进行松弛,在每次松弛时把每条边都更新一下,若在 n-1 次松弛后还能更新,则说明图中有负环,因此无法得出结果,否则就完成。
(通俗的来讲就是:假设 1 号点到 n 号点是可达的,每一个点同时向指向的方向出发,更新相邻的点的最短距离,通过循环 n-1 次操作,若图中不存在负环,则 1 号点一定会到达 n 号点,若图中存在负环,则在 n-1 次松弛后一定还会更新)
具体步骤
bellman - ford算法的具体步骤 for n次 for 所有边 a,b,w (松弛操作) dist[b] = min ( dist[b] , back[a] + w)
注意:back[] 数组是上一次迭代后 dist[] 数组的备份,由于是每个点同时向外出发,因此需要对 dist[]
数组进行备份,若不进行备份会因此发生串联效应,影响到下一个点
注意
是否能到达n号点的判断中需要进行 if ( dist[n] > inf/2 ) 判断,而并非是 if( dist[n] == INF)
判断原因是INF是一个确定的值,并非真正的无穷大,会随着其他数值而受到影响,dist[n]大于某个与INF相同数量级的数即可
bellman - ford算法擅长解决有边数限制的最短路问题
时间复杂度 O(nm)
C++代码
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
const int M = 1e5+10;
const int inf = 0x3f3f3f3f;
struct node{
int a;int b;int w;
}e[M]; //边
// 距离 备份
int dis[N],back[N],n,m,k;
int bellman_ford(){
fill(dis,dis+N,inf);
//memset(dis,0x3f,sizeof(dis)); memset和fill有区别 今天才知道
//cout<<dis[0]<<endl;
dis[1] = 0;
for(int i = 0;i < k;i++){ //k次循环
memcpy(back,dis,sizeof(dis));
for(int j = 0;j < m;j++){
int a = e[j].a , b = e[j].b, w = e[j].w;
dis[b] = min(dis[b],back[a] + w);
//避免给a更新后立马更新b, 这样b一次性最短路径就多了两条边出来
}
}
if(dis[n] > inf/2) cout<<"impossible";
else cout<<dis[n];
}
int main(){
cin>>n>>m>>k;
for(int i = 0 ;i < m;i++){
cin>>e[i].a>>e[i].b>>e[i].w;
}
bellman_ford();
}
Java代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
static int N = 510;
static int M = 100010;
static int n;//总点数
static int m;//总边数
static int k;//最多经过k条边
static int[] dist = new int[N];//从1到点到n号点的距离
static Node[] list = new Node[M];//结构体
static int inf = 0x3f3f3f3f;
static int[] back = new int[N];
public static void bellman_ford(){
Arrays.fill(dist, INF);
dist[1] = 0;
for(int i = 0;i < k;i++){
back = Arrays.copyOf(dist, n + 1);
for(int j = 0;j < m;j++){
Node node = list[j];
int a = node.a;
int b = node.b;
int c = node.c;
dist[b] = Math.min(dist[b], back[a] + c);
}
}
if(dist[n] > inf/2) System.out.println("impossible");
else System.out.println(dist[n]);
}
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String[] str1 = reader.readLine().split(" ");
n = Integer.parseInt(str1[0]);
m = Integer.parseInt(str1[1]);
k = Integer.parseInt(str1[2]);
for(int i = 0;i < m;i++){
String[] str2 = reader.readLine().split(" ");
int a = Integer.parseInt(str2[0]);
int b = Integer.parseInt(str2[1]);
int c = Integer.parseInt(str2[2]);
list[i] = new Node(a,b,c);
}
bellman_ford();
}
}
class Node
{
int a, b, c;
public Node(int a,int b,int c)
{
this.a = a;
this.b = b;
this.c = c;
}
}