图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法

这篇具有很好参考价值的文章主要介绍了图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

0 代码仓库

https://github.com/Chufeng-Jiang/Graph-Theory/tree/main/src/Chapter11_Min_Path

1 Dijkstra算法

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法,图论,图论,算法

2 Dijkstra算法的实现

2.1 设置距离数组

//用于存储从源点到当前节点的距离,并初始化
dis = new int[G.V()];
Arrays.fill(dis, Integer.MAX_VALUE);
dis[s] = 0;

2.2 找到当前路径的最小值 curdis,及对应的该顶点cur

int cur = -1, curdis = Integer.MAX_VALUE;

for(int v = 0; v < G.V(); v ++)
    if(!visited[v] && dis[v] < curdis){
        curdis = dis[v];
        cur = v;
    }

2.3 更新权重

visited[cur] = true;
for(int w: G.adj(cur))
   if(!visited[w]){
       if(dis[cur] + G.getWeight(cur, w) < dis[w])
           dis[w] = dis[cur] + G.getWeight(cur, w);
   }

2.4 其他接口

2.4.1 判断某个顶点的连通性

public boolean isConnectedTo(int v){
    G.validateVertex(v);
    return visited[v];
}

2.4.2 求源点s到某个顶点的最短路径

public int distTo(int v){
    G.validateVertex(v);
    return dis[v];
}

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法,图论,图论,算法

3使用优先队列优化-Dijkstra算法

3.1 设计内部类node

存放节点编号和距离

    private class Node implements Comparable<Node>{

        public int v, dis;

        public Node(int v, int dis){
            this.v = v;
            this.dis = dis;
        }

        @Override
        public int compareTo(Node another){
            return dis - another.dis;
        }
    }

3.2 入队

PriorityQueue<Node> pq = new PriorityQueue<Node>();

pq.add(new Node(s, 0));

这里的缺点就是,更新node时候,会重复添加节点相同的node,但是路径值不一样。不影响最后结果。

while(!pq.isEmpty()){

    int cur = pq.remove().v;
    if(visited[cur]) continue;

    visited[cur] = true;
    for(int w: G.adj(cur))
        if(!visited[w]){
            if(dis[cur] + G.getWeight(cur, w) < dis[w]){
                dis[w] = dis[cur] + G.getWeight(cur, w);
                pq.add(new Node(w, dis[w]));
                pre[w] = cur;
            }
        }
}

3.3 记录路径

private int[] pre;
  • 更新pre数组
for(int w: G.adj(cur))
    if(!visited[w]){
        if(dis[cur] + G.getWeight(cur, w) < dis[w]){
            dis[w] = dis[cur] + G.getWeight(cur, w);
            pq.add(new Node(w, dis[w]));
            pre[w] = cur;
        }
    }
  • 输出路径
    public Iterable<Integer> path(int t){

        ArrayList<Integer> res = new ArrayList<>();
        if(!isConnectedTo(t)) return res;

        int cur = t;
        while(cur != s){
            res.add(cur);
            cur = pre[cur];
        }
        res.add(s);

        Collections.reverse(res);
        return res;
    }

3.4 整体

package Chapter11_Min_Path.Dijkstra_pq;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.PriorityQueue;


public class Dijkstra {

    private WeightedGraph G;
    private int s;
    private int[] dis;
    private boolean[] visited;
    private int[] pre;

    private class Node implements Comparable<Node>{

        public int v, dis;

        public Node(int v, int dis){
            this.v = v;
            this.dis = dis;
        }

        @Override
        public int compareTo(Node another){
            return dis - another.dis;
        }
    }

    public Dijkstra(WeightedGraph G, int s){

        this.G = G;

        G.validateVertex(s);
        this.s = s;

        dis = new int[G.V()];
        Arrays.fill(dis, Integer.MAX_VALUE);

        pre = new int[G.V()];
        Arrays.fill(pre, -1);

        dis[s] = 0;
        pre[s] = s;
        visited = new boolean[G.V()];

        PriorityQueue<Node> pq = new PriorityQueue<Node>();
        pq.add(new Node(s, 0));

        while(!pq.isEmpty()){

            int cur = pq.remove().v;
            if(visited[cur]) continue;

            visited[cur] = true;
            for(int w: G.adj(cur))
                if(!visited[w]){
                    if(dis[cur] + G.getWeight(cur, w) < dis[w]){
                        dis[w] = dis[cur] + G.getWeight(cur, w);
                        pq.add(new Node(w, dis[w]));
                        pre[w] = cur;
                    }
                }
        }
    }

    public boolean isConnectedTo(int v){

        G.validateVertex(v);
        return visited[v];
    }

    public int distTo(int v){

        G.validateVertex(v);
        return dis[v];
    }

    public Iterable<Integer> path(int t){

        ArrayList<Integer> res = new ArrayList<>();
        if(!isConnectedTo(t)) return res;

        int cur = t;
        while(cur != s){
            res.add(cur);
            cur = pre[cur];
        }
        res.add(s);

        Collections.reverse(res);
        return res;
    }

    static public void main(String[] args){

        WeightedGraph g = new WeightedGraph("g.txt");
        Dijkstra dij = new Dijkstra(g, 0);
        for(int v = 0; v < g.V(); v ++)
            System.out.print(dij.distTo(v) + " ");
        System.out.println();

        System.out.println(dij.path(3));
    }
}

4 Bellman-Ford算法

4.1 松弛操作

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法,图论,图论,算法

4.2 负权环

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法,图论,图论,算法

4.3 算法思想

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法,图论,图论,算法

4.4 进行V-1次松弛操作

// 进行V-1次松弛操作
for(int pass = 1; pass < G.V(); pass ++){
    for(int v = 0; v < G.V(); v ++)
        for(int w: G.adj(v))
            if(dis[v] != Integer.MAX_VALUE && // 避免对无穷值的点进行松弛操作
               dis[v] + G.getWeight(v, w) < dis[w]){
                dis[w] = dis[v] + G.getWeight(v, w);
                pre[w] = v;
            }
}

4.5 判断负权环

// 多进行一次操作,如果还有更新,那么存在负权换
for(int v = 0; v < G.V(); v ++)
    for(int w : G.adj(v))
        if(dis[v] != Integer.MAX_VALUE &&
           dis[v] + G.getWeight(v, w) < dis[w])
            hasNegCycle = true;

4.6 整体

package Chapter11_Min_Path.BellmanFord;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class BellmanFord {

    private WeightedGraph G;
    private int s;
    private int[] dis;
    private int[] pre;
    private boolean hasNegCycle = false;

    public BellmanFord(WeightedGraph G, int s){

        this.G = G;

        G.validateVertex(s);
        this.s = s;

        dis = new int[G.V()];
        Arrays.fill(dis, Integer.MAX_VALUE);
        dis[s] = 0;

        pre = new int[G.V()];
        Arrays.fill(pre, -1);

        // 进行V-1次松弛操作
        for(int pass = 1; pass < G.V(); pass ++){
            for(int v = 0; v < G.V(); v ++)
                for(int w: G.adj(v))
                    if(dis[v] != Integer.MAX_VALUE && // 避免对无穷值的点进行松弛操作
                       dis[v] + G.getWeight(v, w) < dis[w]){
                        dis[w] = dis[v] + G.getWeight(v, w);
                        pre[w] = v;
                    }
        }

        // 多进行一次操作,如果还有更新,那么存在负权换
        for(int v = 0; v < G.V(); v ++)
            for(int w : G.adj(v))
                if(dis[v] != Integer.MAX_VALUE &&
                   dis[v] + G.getWeight(v, w) < dis[w])
                    hasNegCycle = true;
    }

    public boolean hasNegativeCycle(){
        return hasNegCycle;
    }

    public boolean isConnectedTo(int v){
        G.validateVertex(v);
        return dis[v] != Integer.MAX_VALUE;
    }

    public int distTo(int v){
        G.validateVertex(v);
        if(hasNegCycle) throw new RuntimeException("exist negative cycle.");
        return dis[v];
    }

    public Iterable<Integer> path(int t){

        ArrayList<Integer> res = new ArrayList<Integer>();
        if(!isConnectedTo(t)) return res;

        int cur = t;
        while(cur != s){
            res.add(cur);
            cur = pre[cur];
        }
        res.add(s);

        Collections.reverse(res);
        return res;
    }

    static public void main(String[] args){

        WeightedGraph g = new WeightedGraph("gw2.txt");
        BellmanFord bf = new BellmanFord(g, 0);
        if(!bf.hasNegativeCycle()){
            for(int v = 0; v < g.V(); v ++)
                System.out.print(bf.distTo(v) + " ");
            System.out.println();

            System.out.println(bf.path(3));
        }
        else
            System.out.println("exist negative cycle.");

        WeightedGraph g2 = new WeightedGraph("g2.txt");
        BellmanFord bf2 = new BellmanFord(g2, 0);
        if(!bf2.hasNegativeCycle()){
            for(int v = 0; v < g2.V(); v ++)
                System.out.print(bf2.distTo(v) + " ");
            System.out.println();
        }
        else
            System.out.println("exist negative cycle.");
    }
}

5 Floyed算法

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法,图论,图论,算法

5.1 设置记录两点最短距离的数组,并初始化两点之间的距离

private int[][] dis;
  • 初始化两点之间的距离
for(int v = 0; v < G.V(); v ++){
    dis[v][v] = 0;
    for(int w: G.adj(v))
        dis[v][w] = G.getWeight(v, w);
}

5.2 更新两点之间的距离

第一重循环:测试两点之间经过点t是否存在更短的路径。

        for(int t = 0; t < G.V(); t ++)
        
            for(int v = 0; v < G.V(); v ++)
                for(int w = 0; w < G.V(); w ++)
                    if(dis[v][t] != Integer.MAX_VALUE && dis[t][w] != Integer.MAX_VALUE
                       && dis[v][t] + dis[t][w] < dis[v][w])
                        dis[v][w] = dis[v][t] + dis[t][w];

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法,图论,图论,算法
图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法,图论,图论,算法文章来源地址https://www.toymoban.com/news/detail-758348.html

到了这里,关于图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法基础复盘笔记Day06【搜索与图论】—— Dijkstra、bellman-ford、spfa、Floyd

    ❤ 作者主页:欢迎来到我的技术博客😎 ❀ 个人介绍:大家好,本人热衷于 Java后端开发 ,欢迎来交流学习哦!( ̄▽ ̄)~* 🍊 如果文章对您有帮助,记得 关注 、 点赞 、 收藏 、 评论 ⭐️⭐️⭐️ 📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉 1. 题目

    2023年04月22日
    浏览(46)
  • 单源最短路径(spfa,Dijkstra, bellman-ford)

    目录  Dijkstra 原理:基于贪心。 为什么 Dijkstra 不能处理有负边的情况 Bellman-ford 原理:动态规划, 实质见floyd的另一篇博客 1,能找负环, 2,有变数限制的最短路径 spfa 原理 spfa怎么求负环, 原理:基于贪心。 第一步 初始化距离,dist[1] = 0, 一号点到起点的距离为0, 其他点

    2024年02月04日
    浏览(50)
  • 最短路之 Bellman-ford 算法

    若有向图有n个点,m条边 。 扫描所有边,对每条边进行一次松弛(即对a,b为端点 , 权重为w的边,dist[b] = min(dist[a] , dist[a] + w )) 重复此流程(最多重复n次)直到没有更新操作发生 给你一张 n 个顶点 m 条边的有向简单图,顶点编号从 1 到 n,每条边都有一个边权,边权为非

    2024年02月17日
    浏览(40)
  • 最短路径算法 | Bellman-Ford Algorithm

    我们在之前的文章中已经讨论了最短路径算法中最经典的Dijkstra‘s Algorithm。然而,Dijkstra\\\'s Algorithm虽然好用,却仍然存在一些缺点即无法解决带有负权重路线的问题,改进后的Dijkstra算法尽管可以解决一些简单的负权重问题,但仍然无法解决带有负循环的图的最短路径问题。

    2024年02月08日
    浏览(51)
  • 图搜索算法详解 - DFS、BFS、Bellman-Ford、Dijkstra

    图搜索算法是许多应用程序的基础,例如社交网络分析、路径规划、数据挖掘和推荐系统。在本文中,我们将深入探讨图搜索算法的世界,探索它们的定义、重要性和实际应用。 图搜索算法是一种用于遍历图的技术,图是由 关系 连接的 节点集合 。在社交网络、网页或生物

    2024年02月16日
    浏览(42)
  • Bellman-Ford-贝尔曼-福特-算法求最短路-负环

    Bellman-Ford(贝尔曼-福特)算法基于松弛操作的单源最短路算法。 e[u]存u点的出边的邻点和边权,d[u]存u点到源点的距离。 初始化,ds]=0,d[其它点]=+o; 执行多轮循环。每轮循环,对所有边都尝试进行一次松弛操作; 当一轮循环中没有成功的松弛操作时,算法停止 为什么最坏需要

    2024年02月13日
    浏览(38)
  • C++ | 数据结构与算法 | 单源最短路径 | Dijkstra && Bellman Ford

    (关于代码实现的图结构,可以看图结构的实现这篇文章) Dijkstra的实现与Prim的实现相似,两者都是通过贪心思想实现,它们有什么不同呢?首先Prim算法是针对无向图的最小生成树的,而Dijkstra算法是针对 有向图 的最短路径生成。一个的目的是连接图中的所有顶点,生成一

    2024年02月03日
    浏览(49)
  • 最短路问题 Bellman-Ford(单源最短路径)(图解)

    对于边(u,v),用dist(u)和(u,v)的和尝试更新dist(v):                          dist(v) = min(dist(v) , dist(u)+l(u,v) 注:dist(i)为源点(起点)到i点的距离,l(u,v)为u-v的边权。 Bellman-Ford的基本操作是进行多次迭代,每一轮迭代对图上所有边进行松弛操作,直到

    2024年02月09日
    浏览(38)
  • 图论详解——Bellman-Ford(清晰易懂)

    开学第一周,晚上属实作业有点乱 于是就拖更了一周 今天我们来讲解一下图论最短路径算法中 最简单 最清晰易懂 同时时间复杂度最高的算法 它的时间复杂度能达到O(VE)(点的数量*边的数量) 在学习Bellman-Ford之前,你需要先学会链式前向星 大家可以上网或者其他途径自行

    2024年02月06日
    浏览(44)
  • 图论:最短路(dijkstra算法、bellman算法、spfa算法、floyd算法)详细版

    终于是学完了,这个最短路我学了好几天,当然也学了别的算法啦,也是非常的累啊。 话不多说下面看看最短路问题吧。 最短路问题是有向图,要求的是图中一个点到起点的距离,其中我们要输入点和点之间的距离,来求最短路。 下面分为几类题目: 单源汇最短路--一个起

    2024年01月21日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包