Bellman-Ford算法

来源:互联网 发布:mysql 保持数据一致性 编辑:程序博客网 时间:2024/04/29 17:24

Bellman-ford算法是求含负权图的单源最短路径算法,效率很低,但代码很容易写。即进行持续地松弛(原文是这么写的,为什么要叫松弛,争议很大),每次松弛把每条边都更新一下,若n-1次松弛后还能更新,则说明图中有负环,无法得出结果,否则就成功完成。Bellman-ford算法有一个小优化:每次松弛先设一个标识flag,初值为FALSE,若有边更新则赋值为TRUE,最终如果还是FALSE则直接成功退出。Bellman-ford算法浪费了许多时间做没有必要的松弛,而SPFA算法用队列进行了优化,效果十分显著,高效难以想象。SPFA还有SLF,LLL,滚动数组等优化。
Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题。对于给定的带权(有向或无向)图 G=(V,E),其源点为s,加权函数 w是 边集 E 的映射。对图G运行Bellman-Ford算法的结果是一个布尔值,表明图中是否存在着一个从源点s可达的负权回路。若不存在这样的回路,算法将给出从源点s到 图G的任意顶点v的最短路径d[v]。

package com.gloomy.graph;import java.util.ArrayDeque;import java.util.ArrayList;import java.util.List;import java.util.Queue;/** * 处理存在负边值的最短路径算法 Bellman-Ford算法优化或的SPFA算法 * (无负值圈存在) *  *  * @author 过路的守望 * */public class WeightedNegative {    public static void main(String[] args) {        Vertex A = new Vertex("A");        Vertex B = new Vertex("B");        Vertex C = new Vertex("C");        Vertex D = new Vertex("D");        Vertex E = new Vertex("E");        Vertex F = new Vertex("F");        Vertex G = new Vertex("G");        A.getAdjacentList().add(B);        A.getAdjacentList().add(D);        A.getAdjacentEdgesMap().put(B, 2);        A.getAdjacentEdgesMap().put(D, 1);        B.getAdjacentList().add(E);        B.getAdjacentEdgesMap().put(E, -11);        C.getAdjacentList().add(A);        C.getAdjacentEdgesMap().put(A, 4);        C.getAdjacentList().add(F);        C.getAdjacentEdgesMap().put(F, 2);        D.getAdjacentList().add(C);        D.getAdjacentEdgesMap().put(C, 5);        D.getAdjacentList().add(F);        D.getAdjacentEdgesMap().put(F, 6);        D.getAdjacentList().add(G);        D.getAdjacentEdgesMap().put(G, 2);        E.getAdjacentList().add(G);        E.getAdjacentEdgesMap().put(G, 6);        E.getAdjacentList().add(D);        E.getAdjacentEdgesMap().put(D, 1);        G.getAdjacentList().add(F);        G.getAdjacentEdgesMap().put(F, 1);        List<Vertex> vertexs = new ArrayList<Vertex>();        vertexs.add(A);        vertexs.add(B);        vertexs.add(C);        vertexs.add(D);        vertexs.add(E);        vertexs.add(F);        vertexs.add(G);        WeightedNegative weightedNegative = new WeightedNegative();        weightedNegative.weightedNegative(A, vertexs);    }    /**     * 对算法进行优化,即每遍处理只对特定顶点出发的边做松弛操作。可以将发生变化的顶点的记录下来,在下一遍处理时对一这些顶点为源点的边做松弛操作。     * 我们使用队列结构来存储这些顶点     *      * @param s     * @param vertexs     */    public void weightedNegative(Vertex s, List<Vertex> vertexs) {        Queue<Vertex> queue = new ArrayDeque<Vertex>();        /*         * 将起始顶点的路径长度置为0,加入队列中         */        s.setDist(0);        queue.offer(s);        Vertex curVertex = null;        /*         * 一直循环到队列为空退出         */        while (!queue.isEmpty()) {            curVertex = queue.poll();            for (Vertex vertex : curVertex.getAdjacentList()) {                /*                 * 更新起始顶点到当前顶点的路径长度                 */                if (vertex.getDist() > curVertex.getDist()                        + curVertex.getAdjacentEdgesMap().get(vertex)) {                    vertex.setDist(curVertex.getDist()                            + curVertex.getAdjacentEdgesMap().get(vertex));                    vertex.setPreVertex(curVertex);                    /*                     * 算法每遍处理对于各条边都进行检查将是很大的浪费,因为有大量的边并不会导致有效的松弛。事实上,                     * 唯一可能导致调整的边仅为某些特定顶点出发的边:这些顶点的值在上一遍处理中发生了变化。                     */                    if (!queue.contains(vertex)) {                        queue.offer(vertex);                    }                }            }        }        for (Vertex vertex5 : vertexs) {            printPath(vertex5, vertexs.get(0));            System.out.println();        }    }    private void printPath(Vertex vertex, Vertex source) {        if (vertex.getPreVertex() != null) {            printPath(vertex.getPreVertex(), source);            System.out.print(" " + "to" + " ");        }        System.out.print(vertex.getLabel());    }}
0 0
原创粉丝点击