当前位置: 首页 > news >正文

java---SPFA算法---判断负权回路(每日一道算法2022.8.31)

注意事项:
学习SPFA判断负环之前推荐先理解如何使用SPFA来找单源最短路,并且代码中涉及到邻接图用单链表数组模拟存储,之前写的文章链接:
java-单链表数组模拟
java-SPFA最短路

负环的定义:一条边权之和为负数的回路
图例: (BCD的边权总和为负,而且BCD是个环,BCD就是个负权回路)
请添加图片描述

题目
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数
请你判断图中是否存在负权回路

第一行包含整数 n 和 m
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z

输入:
3 3
1 2 -1
2 3 4
3 1 -4
输出:
Yes
public class 最短路_SPFA_判断负环 {
    //h,e,ne模拟邻接图,w存储边的权重,dist存储起点到当前节点的距离,st表示当前这个点是不是在队列当中,千万不要和dijkstra的st搞混了
    //count存储的是从起点到当前节点一共走过了几条边
    public static int N = 1000010, index = 0, n, m;
    public static int[] h = new int[N], e = new int[N], ne = new int[N], w = new int[N];
    public static int[] dist = new int[N], count = new int[N];
    public static boolean[] st = new boolean[N];

    public static void main(String[] args) {
        //初始化,链表head全部为正无穷,n是点的个数,m是边的个数
        Scanner in = new Scanner(System.in);
        n = in.nextInt(); m = in.nextInt();
        Arrays.fill(h, -1);

        while (m-- > 0) {
            int x = in.nextInt(), y = in.nextInt(), c = in.nextInt();
            add(x, y, c);
        }

        if (SPFA()) System.out.println("Yes");
        else System.out.println("No");
    }

    //邻接表的插入操作,类似于单链表模拟
    public static void add (int x, int y, int c){
        e[index] = y;
        w[index] = c;
        ne[index] = h[x];
        h[x] = index++;
    }

    public static boolean SPFA() {
        //这里不需要对dist进行正无穷覆盖和初始化,因为根本不关心最短路的事
        //将每一个节点都推入到队列中,这是防止起点和负环之间不存在连接,干脆就全推一遍
        Queue<Integer> q = new ArrayDeque<>();
        for (int i = 1; i<=n; i++) {
            st[i] = true;
            q.add(i);
        }

        //这里的整体思路还是SPFA的思路不变
        while (q.size() > 0){
            int t = q.poll();
            st[t] = false;

            for (int i = h[t]; i!=-1; i = ne[i]) {
                int j = e[i];

                //着重说一下这个地方,count[n]代表起点到n点需要经过几条边,而j是t的下一个点,所以起点到j的距离就是t+1
                //而因为有负环的存在,负环中的点到起点的count就会被无限次的更新
                //那么当起点到当前节点经过的边数大于等于n时,也就说明图中至少有n+1个点存在,这就不合理了,说明存在负环,返回True
                if (dist[j] > dist[t] + w[i]) {
                    dist[j] = dist[t] + w[i];

                    count[j] = count[t] + 1;
                    if(count[j] >= n) return true;

                    if (!st[j]) {
                        q.add(j);
                        st[j] = true;
                    }
                }
            }
        }

        //如果没遇到负环,返回false
        return false;
    }
}

你们可能会说
“啊!你这个坏东西,把昨天的SPFA改了两行代码改了点注释就发出来水一题,好意思吗你!”
我只能回答…水题真是太爽啦!嘿嘿嘿

声明:算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流

相关文章:

  • 操作系统(Linux)
  • 基础 | 并发编程 - [LockSupport]
  • Uboot命令应用
  • kettle-实现不同数据库之间的数据交换
  • OPPO小布4.0:软件定义硬件,智能定义“助手”
  • python获取模块文件路径
  • java计算机毕业设计企业人事管理系统源码+数据库+系统+lw文档+mybatis+运行部署
  • 机器学习算法1---KNN
  • Java--Spring事务
  • 卷妹带你回顾Java基础每日更新Day12
  • UM5006-RT-Thread ART-Pi 数据 flash 擦写手册
  • 【Halcon知识】外轮廓线的算子
  • 能安装Chrome扩展和油猴脚本的手机浏览器
  • 使用Android studio开发一个数独游戏APP 系列第一讲
  • 如何在深度学习中使用自动混合精度训练
  • ES6指北【2】—— 箭头函数
  • Android框架之Volley
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • iOS编译提示和导航提示
  • Java 最常见的 200+ 面试题:面试必备
  • linux学习笔记
  • Markdown 语法简单说明
  • nodejs:开发并发布一个nodejs包
  • windows下使用nginx调试简介
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 大数据与云计算学习:数据分析(二)
  • 浮现式设计
  • 聊一聊前端的监控
  • 那些年我们用过的显示性能指标
  • 排序(1):冒泡排序
  • 七牛云假注销小指南
  • 驱动程序原理
  • 入门级的git使用指北
  • 算法-插入排序
  • 学习笔记TF060:图像语音结合,看图说话
  • 一个项目push到多个远程Git仓库
  • ​io --- 处理流的核心工具​
  • #include到底该写在哪
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • %@ page import=%的用法
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (70min)字节暑假实习二面(已挂)
  • (LeetCode 49)Anagrams
  • (分布式缓存)Redis分片集群
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (篇九)MySQL常用内置函数
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (五)IO流之ByteArrayInput/OutputStream
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (转载)hibernate缓存
  • (转载)微软数据挖掘算法:Microsoft 时序算法(5)
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • *p++,*(p++),*++p,(*p)++区别?
  • .CSS-hover 的解释
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案