算法思想
java
迭代n次 即循环n次
遍历所有边,对于每一条边(a,b,v)表示a->b的权值为v
若从起点到b的距离大于从起点到a的距离+a到b的距离就更新
这里代码中的体现在于dist[b] = min(dist[b],dist[a]+v])
没了
循环n次,对于所有的边一定满足
dist[b] <= dist[a]+w
,这东西叫做三角不等式,更新一次叫做松弛操作
看弹幕的时候看到了一个差分约束系统
挺高大上的
适用情况
适用于有负权边
的最短路问题,但对于负权回路没有办法,但可以判定有没有负权回路
有边数限制
也可以用,注意若有边数限制,需要加上一个备份数组
,防止发生串联更新
,关于这个串联更新
的意思就是说,a点被更新了,拿着更新后的a点去更新其他点,而其他点需要的是更新前的a点的值,
负权回路与最短路径的存在性的相关性问题
只要负权回路不在最短路径上,那么就存在最短路径
比如1->2 2是终点,存在负权回路,但是也存在最短路径
判定有没有负权回路
它可以判定,但是一般不用这个算法,用
SPFA
,因为时间复杂度大
迭代了k
次,k
的含义从1号点经过不少于k条边走到每个点的最短路的距离,若第n迭代的时候又更新了某条边的话,存在一条边数是大于等于n的最短路径,那么就可以判定是有负权回路,
我的理解就是 n个点的最短路径只有n-1条边,若大于等于了n可以判定有环,而且还是更新后的(也就是说当前值要比上一次的值要小)
时间复杂度
设边数为m,那么时间复杂度就是O(nm),n是迭代的次数
java
迭代n次 即循环n次
遍历所有边,对于每一条边(a,b,v)表示a->b的权值为v
若从起点到b的距离大于从起点到a的距离+a到b的距离就更新
这里代码中的体现在于dist[b] = min(dist[b],dist[a]+v])
没了
代码
java
import java.util.Arrays;
import java.util.Scanner;
class Edge{
int start,end,weight;
public Edge(int start,int end,int weight){
this.start = start;
this.end = end;
this.weight = weight;
}
}
public class Main{
static int n,m,k,max=(int)1e8;
static int[] dist;
static Edge[] edges;
static int bellman_ford(){
dist[1] =0;
for(int i=0;i<k;i++){
//这个备份数组的作用是防止发生串联更新
int[] backup = Arrays.copyOf(dist,dist.length);
for(Edge item: edges){
if(dist[item.end]>dist[item.start]+item.weight){
dist[item.end] = Math.min(dist[item.end],backup[item.start]+ item.weight);
}
}
}
if(dist[n]>=max/2)
return max/2;
return dist[n];
}
public static void main(String[] args) {
Scanner s= new Scanner(System.in);
n = s.nextInt();
m = s.nextInt();
k = s.nextInt();
edges = new Edge[n];
dist = new int[n+1];
Arrays.fill(dist,max);
for(int i=0;i<n;i++)
edges[i] = new Edge(s.nextInt(),s.nextInt(),s.nextInt());
int res = bellman_ford();
if(res==max/2)
System.out.println("impossible");
else
System.out.println(res);
s.close();
}
}