SPFA + 链式前向星建图【附Java模板】

这篇具有很好参考价值的文章主要介绍了SPFA + 链式前向星建图【附Java模板】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SPFA + 链式前向星建图【附Java模板】

                                                                             SPFA算法是什么?它能解决什么样的问题?          


🌷 仰望天空,妳我亦是行人.✨
🦄 个人主页——微风撞见云的博客🎐
🐳 数据结构与算法专栏的文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺
🪁 希望本文能够给读者带来一定的帮助🌸文章粗浅,敬请批评指正!🐥



🦩SPFA算法的概念

🍐SPFA算法(Shortest Path Faster Algorithm)是一种单源最短路径算法,用于求解带权有向图中某个源点到其他所有点的最短路径。它是对Bellman-Ford算法的优化,通过使用队列来避免重复松弛操作,从而提高了算法的效率。SPFA算法的时间复杂度为O(kE),其中k是一个常数,通常情况下k小于2,因此SPFA算法的时间复杂度可以认为是O(E)


🐸SPFA和Dijkstra的区别

🍋 同样是单源最短路径算法,它和Dijkstra有什么区别?

    🍒 SPFA(Shortest Path Faster Algorithm)Dijkstra算法都是用于解决单源最短路径问题的算法,但它们有以下几个区别

        🪁1.时间复杂度:Dijkstra算法的时间复杂度为O(ElogV),其中E为边数,V为顶点数;而SPFA算法的时间复杂度为O(kE),其中k为常数,一般情况下k小于2,但在最坏情况下,k可以达到V。

        🪁2.实现方式:Dijkstra算法使用堆优化的贪心策略,每次选择当前距离最小的未访问节点进行松弛操作;而SPFA算法使用队列实现,每次选择当前距离最小的未访问节点进行松弛操作。

        🪁3.稳定性:Dijkstra算法对于边权值为负的图无法处理,而SPFA算法可以处理负权边,但是在存在负环的情况下,SPFA算法会进入死循环

        🪁综上,Dijkstra算法适用于边权值为正的图,时间复杂度较低;而SPFA算法适用于边权值为负的图,但时间复杂度较高,且存在负环的情况下会出现问题


🐳SPFA算法的解题步骤

        SPFA算法的解题步骤如下:

🦕1. 初始化:将起点的距离设为0,其余点的距离设为无穷大,将起点加入队列。

🦕2. 进行松弛操作:从队列中取出一个点,遍历其所有邻居节点,如果通过该点可以使邻居节点的距离更短,则更新邻居节点的距离,并将其加入队列中。

🦕3. 重复步骤2,直到队列为空。

🦕4. 如果终点的距离被更新过,则说明存在从起点到终点的路径,输出最短路径长度。

🦕5. 如果终点的距离没有被更新过,则说明不存在从起点到终点的路径。

需要注意的是,为了避免负权边导致的死循环,需要在每次更新距离时判断是否存在负权环,如果存在则说明最短路径不存在。


🦕模板题:“随机数据下的最短路问题”

题目描述
给定 N 个点和 M 条单向道路,每条道路都连接着两个点,每个点都有自己编号,分别为 1 ~ N 。
问你从 S 点出发,到达每个点的最短路径为多少。
输入描述
输入第一行包含三个正整数 N,M,S。
第 2 到 M + 1 行每行包含三个正整数 u,v,w,表示 u→v 之间存在一条距离为 w 的路。
1≤N≤5×10^3 , 1≤M≤5×10^4 , 1≤ui,vi≤N , 0≤wi≤10^9
本题数据随机生成。
输出描述
输出仅一行,共 N 个数,分别表示从编号 S 到编号为 1 ~ N 点的最短距离,两两之间用空格隔开。(如果无法到达则输出 -1)
输入输出样例 示例 1
输入
3 3 1
1 2 1
1 3 5
2 3 2
输出
0 1 3
运行限制
最大运行时间:1s 最大运行内存: 128M

        🦕【模板Code(含判断负环)】

import java.io.*;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;


public class Main {
    static int N = (int) (5e3 + 10), M = (int) (5e4 + 10);
    static int[] head = new int[M], ends = new int[M], next = new int[M], weights = new int[M];//链式前向星
    static boolean[] st = new boolean[N];//表示某个点是否在队列里面,注意并非是否访问过
    static int n, m, s, total;
    static long[] dist = new long[N];
    static long[] cnt = new long[N];//判断是否负环回路;
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

    static void add(int start, int end, int weight) {
        ends[total] = end;
        weights[total] = weight;
        next[total] = head[start];
        head[start] = total++;
    }

    public static void main(String[] args) throws IOException {
        n = nextInt();
        m = nextInt();
        s = nextInt();
        Arrays.fill(head, -1);
        for (int i = 0; i < m; i++) add(nextInt(), nextInt(), nextInt());
        if (SPFA()) System.out.println("存在负环回路");
        else System.out.println("无负环回路");
        for (int i = 1; i <= n; i++) {
            if (dist[i] == Long.MAX_VALUE) out.print("-1" + " ");
            else out.print(dist[i] + " ");
        }
        out.flush();
    }


    static boolean SPFA() {
        Deque<Integer> queue = new ArrayDeque<>();
        Arrays.fill(dist, Long.MAX_VALUE);
        dist[s] = 0;//初始点
        queue.offer(s);
        st[s] = true;
        while (!queue.isEmpty()) {
            int hh = queue.poll();
            st[hh] = false;
            for (int i = head[hh]; i != -1; i = next[i]) {
                int j = ends[i];
                if (dist[j] > dist[hh] + weights[i]) {
                    dist[j] = dist[hh] + weights[i];
                    cnt[j] = cnt[hh] + 1;
                    if (cnt[j] >= n) return true;//判断是否负环回路;
                    if (!st[j]) {// 当前已经加入队列的结点,无需再次加入队列,即便发生了更新也只用更新数值即可,重复添加降低效率
                        queue.offer(j);
                        st[j] = true;
                    }
                }
            }
        }
        return false;
    }

    static int nextInt() throws IOException {
        in.nextToken();
        return (int) in.nval;
    }

}

        🦕【解题Code_AC】

import java.io.*;
import java.util.*;


public class Main {
    static int N = (int) (5e3 + 10), M = (int) (5e4 + 10);
    static int[] head = new int[M], ends = new int[M], next = new int[M], weights = new int[M];
    static boolean[] st = new boolean[N];
    static int n, m, s, total;
    static long[] dist = new long[N];
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));


    static void add(int start, int end, int weight) {
        ends[total] = end;
        weights[total] = weight;
        next[total] = head[start];
        head[start] = total++;
    }

    public static void main(String[] args) throws IOException {
        n = nextInt();
        m = nextInt();
        s = nextInt();
        Arrays.fill(head, -1);
        for (int i = 0; i < m; i++) add(nextInt(), nextInt(), nextInt());
        SPFA();
        for (int i = 1; i <= n; i++) {
            if (dist[i] == Long.MAX_VALUE) out.print("-1" + " ");
            else out.print(dist[i] + " ");
        }
        out.flush();
    }


    static void SPFA() {
        Deque<Integer> queue = new ArrayDeque<>();
        Arrays.fill(dist, Long.MAX_VALUE);
        dist[s] = 0L;
        queue.offer(s);
        st[s] = true;
        while (!queue.isEmpty()) {
            int hh = queue.poll();
            st[hh] = false;
            for (int i = head[hh]; i != -1; i = next[i]) {
                int j = ends[i];
                if (dist[j] > dist[hh] + weights[i]) {
                    dist[j] = dist[hh] + weights[i];
                    if (!st[j]) {
                        queue.offer(j);
                        st[j] = true;
                    }
                }
            }
        }
    }

    static int nextInt() throws IOException {
        in.nextToken();
        return (int) in.nval;
    }

}

SPFA + 链式前向星建图【附Java模板】


🐳结语

    🐬初学一门技术时,总有些许的疑惑,别怕,它们是我们学习路上的点点繁星,帮助我们不断成长。

    🐟文章粗浅,希望对大家有帮助!文章来源地址https://www.toymoban.com/news/detail-455926.html

到了这里,关于SPFA + 链式前向星建图【附Java模板】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 算法复习6.1链式前向星(代码块式理解)

    一号初始节点head[1]=3(cnt=3)指向四号节点 edge[3(cnt=3)],其中edge[3].to=4 即四号节点 ,同时令edge[3].next=(new)cnt 指向下一个 ... (循环) 有点像指针,如果功能不复杂的话,可以直接简写为vector快捷操作  

    2024年02月21日
    浏览(28)
  • 【图论】图的存储--链式前向星存图法以及深度优先遍历图

    无向图 - 就是一种特殊的有向图 - 只用考虑有向图的存储即可 邻接矩阵 邻接表 邻接表 存储结构: (为每一个点开了一个单链表,存储这个点可以到达哪个点) 1 : 3-4-null 2 : 1-4-null 3 : 4-null 4 : null 插入一条新的边 比如要插一条边: 2-3 先找到 2 对应的 单链表 然后将 3 插入到单链表

    2024年04月14日
    浏览(34)
  • 【图论C++】树的重心——教父POJ 3107(链式前向星的使用)

    UpData Log👆 2023.9.26 更新进行中 Statement0🥇 一起进步 Statement1💯 有些描述是个人理解,可能不够标准,但能达其意 树 是 图 的一种 特例 , 树 就是 “没有环” 的 连通图 判断一个 图 是否是一个 树 ,需要满足的条件: 1)树根 :一棵树可以基于 无向图 与 有向图 ,区别在

    2024年02月07日
    浏览(27)
  • 【机器学习】P18 反向传播(导数、微积分、链式法则、前向传播、后向传播流程、神经网络)

    反向传播(back propagation)是一种用于训练神经网络的算法,其作用是计算神经网络中每个参数对损失函数的影响,从而进行参数更新,使得神经网络的预测结果更加准确。 具体来说,反向传播算法首先通过 前向传播 计算神经网络的预测结果,并与实际结果进行比较,得到

    2024年02月04日
    浏览(52)
  • 【模板】负环 问题题解(spfa和bellman解决)

    题目描述 给定一个 n 个点的有向图,请求出图中是否存在 从顶点 11 出发能到达 的负环。 负环的定义是:一条边权之和为负数的回路。 输入格式 本题单测试点有多组测试数据 。 输入的第一行是一个整数 T,表示测试数据的组数。对于每组数据的格式如下: 第一行有两

    2024年02月22日
    浏览(27)
  • 最短路Dijkstra,spfa,图论二分图算法AYIT---ACM训练(模板版)

    最短路Dijkstra,spfa,图论二分图算法AYIT—ACM训练(模板版) A — Dijkstra B — spfa/Dijkstra C — 二分图 D — 二分图 E — 二分图 F — 二分图 G — Dijkstra H — Topsort Dijkstra算法基础模板题 💬 模板演示: 朴素版本Dijkstra: 💬 代码演示: 🚩 运行结果: spfa算法: 💬 代码演示: 🚩

    2024年02月10日
    浏览(34)
  • 数据结构与算法—二叉树数组表示(ArrayBinTree)、二叉树的链式表示(LinkedBinTree)的基于C++模板代码实现

    1、二叉树的顺序表示:ArrayBinTree.h 二叉树的顺序表示法操作方便,但缺点是容易造成存储空间浪费。 这是一个用数组实现的二叉树类模板。它可以创建一个空树,也可以在指定的位置插入结点并设置结点的值,可以删除子树,并支持逐层遍历。使用该类时,需要提供一个元

    2024年02月06日
    浏览(30)
  • Java链式存储LinkedList----与ArrayList比较

    作为一名对技术充满热情的学习者,我一直以来都深刻地体会到知识的广度和深度。在这个不断演变的数字时代,我远非专家,而是一位不断追求进步的旅行者。通过这篇博客,我想分享我在某个领域的学习经验,与大家共同探讨、共同成长。请大家以开放的心态阅读,相信

    2024年01月23日
    浏览(37)
  • 【Java-LangChain:使用 ChatGPT API 搭建系统-6】处理输入-链式 Prompt Chaining Prompts

    在本章中,我们将学习如何通过将复杂任务拆分为一系列简单的子任务来链接多个 Prompt。 您可能会想,为什么要将任务拆分为多个 Prompt,而不是像我们在上一个视频中学习的那样,使用思维链推理一次性完成呢?我们已经证明了语言模型非常擅长遵循复杂的指令,特别是像

    2024年02月07日
    浏览(38)
  • SPFA算法详解

    SPFA 算法是Bellman-ford算法的 队列优化 算法的别称,通常用于求 含负权边的单源最短路径 ,以及 判负权环 。 前置知识:Bellman-ford算法详解_真的没事鸭的博客-CSDN博客 SPFA算法其实就是在Bellman-ford算法基础上的优化。Bellman-ford算法看起来比较傻,每次迭代的话是遍历所有边来

    2023年04月23日
    浏览(37)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包