运用分支限界法。分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。

单源最短路径问题:

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Scanner;
/**
 *
 * @author 刘宁宁
 */
public class BBShortest {
static float[][] a;     //  图G的邻接矩阵
    static int v;           //  起点编号
    static float[] dist;    //  dist[i]是节点i与起点的当前算得的最短距离
    static int[] p;         //  前驱数组

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        System.out.println("请输入结点个数");
        int n = s.nextInt();

        a = new float[n+1][n+1];
        for(int i = 0; i < a.length; i++){
            Arrays.fill(a[i], Float.MAX_VALUE);
        }
        p = new int[n+1];
        dist = new float[n+1];

        System.out.println("请输入边数");
        int e = s.nextInt();
        for (int i = 0; i < e; i++) {
            System.out.println("请输入两点及其距离");
            int previous = s.nextInt();
            int next = s.nextInt();
            a[previous][next] = s.nextFloat();
        }

        shortest(1, dist, p);

        // 从左到右,按列优先依次为1,2,3,,,
        System.out.println("最短距离为:" + dist[n] + "\n最短路径为:");
        back(p[n]);
        System.out.println(n);
    }

    static class HeapNode implements Comparable {
        int i;              // 顶点编号
        float length;       // 当前路长

        public HeapNode(int i, float length) {
            this.i = i;
            this.length = length;
        }

        @Override
        public int compareTo(Object o) {
            float xl = ((HeapNode) o).length;
            if (length < xl) {
                return -1;
            }
            if (length == xl) {
                return 0;
            }
            return 1;
        }
    }

    public static void shortest(int v, float[] dist, int[] p) {
        int n = p.length - 1;
        MinHeap heap = new MinHeap(n);
        //定义源为初始扩展结点
        HeapNode enode = new HeapNode(v, 0);

        //dist[j]表示当前结点j到起点的最短距离,初始化为最大值
        for (int j = 1; j <= n; j++)
            dist[j] = Float.MAX_VALUE;
        dist[v] = 0;

        while (true) {      // 搜索问题的解空间
            for (int j = 1; j <= n; j++)
                // enode.i是当前的扩展节点, enode.length是该节点到起始点的最短距离
                if (a[enode.i][j] < Float.MAX_VALUE && enode.length + a[enode.i][j] < dist[j]) {
                    // enode.i 到顶点j可达,且满足控制约束
                    dist[j] = enode.length + a[enode.i][j];
                    //dist[j]是节点J与起点的当前算得的最短距离
                    p[j] = enode.i;    // p[j]表示p的前驱节点
                    HeapNode node = new HeapNode(j, dist[j]);
                    heap.insert(node);      // 加入活结点优先队列
                }
            if (heap.isEmpty()) break;
            else enode = heap.removeMin();
        }
    }

    static void back(int i){
        if(p[i] == 0){
            System.out.print(i + " -> ");
        }else{
            back(p[i]);
            System.out.print(i + " -> ");
        }
    }
}

// 下标从0开始的最小堆, 子节点 2n+1, 2(n+1)
class MinHeap {
    //存储堆中元素
    private BBShortest.HeapNode[] items ;
    //记录堆中元素个数
    private int total;

    public MinHeap() {

    }

    public MinHeap(int capacity) {
        this.items = new BBShortest.HeapNode[capacity];
        for (int i = 0; i < capacity; i++) {
            this.items[i] = new BBShortest.HeapNode(i, 0);
        }
    }

    //获取队列中元素个数
    public int size() {
        return total;
    }

    //判断队列是否为空
    public boolean isEmpty() {
        return total == 0;
    }

    //判断堆中索引i处的元素是否小于索引j处的元素
    private boolean less(int i, int j) {
        return items[i].compareTo(items[j]) < 0;
    }

    //交换堆中i索引和j索引处的值
    private void swap(int i, int j) {
        BBShortest.HeapNode tmp = items[i];
        items[i] = items[j];
        items[j] = tmp;
    }

    //往堆中插入一个元素
    public void insert(BBShortest.HeapNode t) {
        items[++total] = t;
        swim(total);
    }

    //删除堆中最小元素,并返回这个最小元素
    public BBShortest.HeapNode removeMin() {
        BBShortest.HeapNode min = items[0];
        swap(0, total);
        total--;
        sink(0);
        return min;
    }

    //使用上浮算法,使索引k处的元素能在堆中处于一个正确的位置
    private void swim(int k) {
        //通过循环比较当前节点和其父节点的大小
        while (k > 0) {
            if (less(k, (k - 1) / 2)) { // 若果该节点比父节点
                swap(k, (k - 1) / 2);
            }
            k = (k - 1) / 2;
        }
    }

    //使用下沉算法,使索引k处的元素能在堆中处于一个正确的位置
    private void sink(int k) {
        //通过循环比较当前节点和其子节点中较小值
        while (2 * k + 1 <= total) { // 说明该节点有子节点
            //找到子节点中的较小值
            int min;
            if (2 * k + 2 <= total) { // 有右子节点,选左右子结点中值小的赋值给min
                if (less(2 * k + 1, 2 * k + 2)) {
                    min = 2 * k + 1;
                } else {
                    min = 2 * k + 2;
                }
            } else {
                min = 2 * k + 1;
            }
            //判断当前节点和较小值的大小
            if (less(k, min)) {     //该节点小于两个子节点
                break;
            }
            swap(k, min); //交换该节点和较小子节点
            k = min;
        }
    }
}

结果:

多源最短路径算法java 单源最短路径java_多源最短路径算法java