经典算法之图的最短路径(二):Bellman_Ford算法

Bellman_Ford算法也是一个求图的最短路径的非常经典的算法,它适用于求单源最短路径,相比于同样用于单源最短路径的Dijkstra算法,它的适用范围更广,它可以用于有向图和无向图,并且权值可以为负,如果存在负权回路,可输出提示。

算法的流程就是:每次遍历图中所有边进行松弛(所谓的松弛是这样的——比如说存在一条边e(u,v),权值为w(u,v),如果d(v)>d(u)+w(u,v),则让d(v)=d(u)+w(u,v)),共遍历松弛V-1次(V是点的个数),此时如果不存在负权回路的话,d[i]就是源点到点i 的最短路径,因此再进行一次遍历,查看是否存在d(v)>d(u)+w(u,v),若存在,说明有负权值回路。下面上代码:(同样是偷懒没有正向打印路径)

package classic;

import java.util.Scanner;

public class Bellman_Ford {

    static int start = 0, V = 0, E = 0;
    static int[][] G = null;
    static int[] d = null, pre = null;
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("输入点和边的数目:");
        V = sc.nextInt();//总共有多少个点
        E = sc.nextInt();//总共有多少个边
        
        G = new int[V][V];//用来存放图的信息
        d = new int[V];//用来存放从起点到每个点的最短路径长度
        pre = new int[V];//用来存放每个点在其最短路径上的前一个结点
        
        for(int x=0; x<V; x++){
            for(int y=0; y<V; y++){
                G[x][y] = Integer.MIN_VALUE;
            }
        }
        System.out.println("依次输入每条边的起点、终点和权值:(点的编号从0开始)");
        for(int i=0; i<E; i++){//初始化图
            int u = sc.nextInt();
            int v = sc.nextInt();
            int value = sc.nextInt();
            G[u][v] = value;
            G[v][u] = value;//注意:假如为有向图,则不加这一行!!
        }
        for(int i=0; i<V; i++){//初始化d
            if(i==start)
                d[i] = 0;
            else
                d[i] = Integer.MAX_VALUE/2;
        }
        
        if(!bellman_ford())
            System.out.println("图中存在负权值环");
        else{//打印
            for(int i=0; i<V; i++){
                System.out.println("起点"+start+"到点"+i+"的最短路径长度为:"+d[i]);
                System.out.println("最短路径为:");
                int curv = i;
                System.out.print(i+"<-");
                while(true){
                    curv = pre[curv];
                    if(curv == start)
                        break;
                    System.out.print(curv+"<-");
                }
                System.out.println(start);
            }
        }
        sc.close();
    }
    
    static boolean bellman_ford(){
        for(int i=1; i<V; i++){//对每条边都松弛V-1次
            for(int x=0; x<V; x++){
                for(int y=0; y<V; y++){
                    if(G[x][y]>Integer.MIN_VALUE){//说明有边
                        if(d[y]>d[x]+G[x][y]){
                            d[y] = d[x]+G[x][y];
                            pre[y] = x;
                        }
                    }
                }
            }
        }
        for(int x=0; x<V; x++){
            for(int y=0; y<V; y++){
                if(G[x][y]>Integer.MIN_VALUE){//说明有边
                    if(d[y]>d[x]+G[x][y]){
                        return false;
                    }
                }
            }
        }
        return true;
    }

}

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/silent_strings/article/details/48178429
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞