图论算法(三)--最短路径 的Bellman-Flod [ 带负权值图 ] 的解法(JAVA )

Bellman-Flod算法

对于带有负权值的图,我们已经不能通过Dijkstra算法进行求解了
原因:Dijkstra每次都会找一个距源点(设为s)最近的点,然后将该距离定为这个点到源点的最短路径;如果一个顶点u被加入了book[i])( book[i] == 1 说明这个s到u的路径权值已被记录,不可再更改),但是如果存在v到u的权值为负,那么s经v到u到值要更小。
例如:
Dijkstra
如果用Dijkstra跑只能得到2这个结果,但实际结果应该是1才对
s—->u 2
s—->v—-> 1


为解决带负权值的问题,这里需要用到Bellman-Flod算法
问题描述:有如下带负权值的图,求从1号点到其他各点的最短路径长度

city
Input:
5 5
2 3 2
1 2 -3
1 5 5
4 5 2
3 4 3

Output:
0 -3 -1 2 4

import java.util.Scanner;
public class minPath {static int[] u = new int[10];static int[] v = new int[10];static int[] w = new int[10];static int[] dis = new int[10];static int n, m;static Scanner input  = new Scanner(System.in);public static void main(String[] args) {n = input.nextInt();m = input.nextInt();for (int i = 1; i <= m; i++) {u[i] = input.nextInt();v[i] = input.nextInt();w[i] = input.nextInt();}for (int i = 1; i <= n; i++) {dis[i] = 99999999;}dis[1] = 0;bellmanFlod();for (int i = 1; i <= n; i++) {System.out.print(dis[i] + " ");}}private static void bellmanFlod() {/*** 由离散数学的理论得出,在一个n个顶点的图中,任意两点之间的最短路径最多包含n-1条边* */for (int i = 1; i <= n - 1; i++) {for (int j = 1; j <= m; j++) {if (dis[v[j]] > dis[u[j]] + w[j]) {dis[v[j]] = dis[u[j]] + w[j];}}}}
}

时间复杂度:O(NM)

算法优化

优化版本一

优化原因:在实际操作中,很多时候不会进行n-1次,毕竟不是每个点都会达到n-1条边的情况的,因此当不在能更新之后,我们就可以终止程序了,即使现在还没进行到第n-1阶段。

优化方法:添加一个一维数组备份来dis,如果新一轮的松弛中数组没有发生变化,则可以提前跳出循环。

import java.util.Scanner;public class minPath {static int[] u = new int[10];static int[] v = new int[10];static int[] w = new int[10];static int[] dis = new int[10];static int[] bak = new int[10];static int n, m;static int check, flag;static Scanner input  = new Scanner(System.in);public static void main(String[] args) {n = input.nextInt();m = input.nextInt();for (int i = 1; i <= m; i++) {u[i] = input.nextInt();v[i] = input.nextInt();w[i] = input.nextInt();}for (int i = 1; i <= n; i++) {dis[i] = 99999999;}dis[1] = 0;bellmanFlod();if (flag == 1) {System.out.println("此图含有负权回路");} else {for (int j = 1; j <= n; j++) {System.out.print(dis[j] + " ");}}}private static void bellmanFlod() {/*** 由离散数学的理论得出,在一个n个顶点的图中,任意两点之间的最短路径最多包含n-1条边* */for (int i = 1; i <= n - 1; i++) {bak[i] = dis[i];for (int j = 1; j <= m; j++) {if (dis[v[j]] > dis[u[j]] + w[j]) {dis[v[j]] = dis[u[j]] + w[j];}}/*** 检测dis是否还在变化* */check = 0;for (int j = 1; j <= n; j++) {if (bak[i] != dis[i]) {check = 1;break;}if (check == 0) {break;}}/*** 检测负权回路* 原理:最短路径所包含的边做多为n-1条,在进行n-1次松弛之后如果还能继续松弛成功,* 那说明此图必定含有负权回路* */flag = 0;for (int j = 1; j <= m; j++) {if (dis[v[i]] > dis[u[i]] + w[i]) {flag = 1;}}}}
}

优化原因:因为最短路径做多有n-1条边,所以Bellman-Ford算法做多有n-1个阶段。而每个阶段都要对每条边进行“松弛操作”,使得“估计值”变为“确定值”。而对于本阶段来说,上个阶段松弛完的结果是不会再改变的,而原算法每个阶段都会重新计算,浪费时间。

优化方法:每次仅对最短路“估计值”变化为“确定值”的顶点的所有出边执行松弛操作,可以采用队列进行优化
时间复杂度:O(NM)

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;public class minPath {static int[] u = new int[8];static int[] v = new int[8];static int[] w = new int[8];/*** first 要比 n 的值大1* next  要比 m 的值大1* */static int[] first = new int[6];static int[] next = new int[8];static int[] dis = new int[6];static int[] book = new int[6];static int n, m;static Queue<Integer> queue = new LinkedList<>();static Scanner input = new Scanner(System.in);public static void main(String[] args) {n = input.nextInt();m = input.nextInt();for (int i = 1; i <= n; i++) {dis[i] = 99999999;}dis[1] = 0;for (int i = 1; i <= n; i++) {first[i] = -1;}for (int i = 1; i <= m; i++) {u[i] = input.nextInt();v[i] = input.nextInt();w[i] = input.nextInt();/*** 建立邻接表的关键语句!!!* */next[i] = first[u[i]];first[u[i]] = i;}queue.offer(1);book[1] = 1;bellomanFlodPlus();for (int i = 1; i <= n; i++) {System.out.print(dis[i] + " ");}}private static void bellomanFlodPlus() {while (!queue.isEmpty()) {/*** 当前的队首元素* */int k = first[queue.peek()];while (k != -1) {if (dis[v[k]] > dis[u[k]] + w[k]) {dis[v[k]] = dis[u[k]] + w[k];/*** 用数组来判断v[k]是否已经在队列中* 不使用数组进行记录的话,要迭代队列,十分不方便* */if(book[v[k]] == 0) {queue.offer(v[k]);book[v[k]] = 1;}}k = next[k];}book[queue.peek()] = 0;queue.remove();}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569827.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloud介绍(一)

1.1 SpringCloud介绍 1.1.1 微服务架构演化 简而言之&#xff0c;微服务就是开发一组小型服务的方式来开发一个独立的应用系统&#xff0c;每个小型服务都运行在自己的进程中&#xff0c;并采用HTTP资源API轻量级的机制来互相通信。这些服务围绕业务功能进行构建&…

最短路径问题总结,时间复杂度,空间复杂度对比(JAVA)

最短路径问题总结 图中还有些地方没有完善&#xff0c;但是一时也没没办法解决&#xff0c;希望大家知道的能够提供一下表中不足的地方&#xff0c;万分感谢&#xff01;&#xff01;&#xff01; 最短路径算法&#xff08;一&#xff09;–DFS/BFS求解&#xff08;JAVA &…

树--树的基本性质(JAVA)

前几篇文章介绍了图的搜索算法&#xff0c;最短路径算法&#xff0c;接下来介绍树&#xff1a; 树和图 树实际上就是不含回路的无向连通图 虽然树不连通&#xff0c;没有回路了&#xff0c;但是这也使得树这种数据结构有了更多的特性&#xff1a; 1.一棵树中的任意两个结点…

P1272 重建道路

一开始状态定义错了……所以没有对qwq&#xff0c;以及有几个坑qwq…… 首先 f [ i ] [ j ] 表示以 i 为根的子树&#xff0c;切除 j 个节点所需要切除的最小边数&#xff0c;而我一开始定义的是表示以 i 为根的子树&#xff0c;切除后生成一颗有 j 个节点的子树&#xff0c;所…

排序算法(二)--堆排序(JAVA)

堆的一个很重要的应用就是堆排序&#xff0c;和快速排序一样&#xff0c;堆排序的时间复杂度也是O(NlgN) 堆排序的实现思路一&#xff1a; 1.创建小根堆 2.每次删除顶部元素并将顶部元素输出&#xff08;删除的函数中有调整的过程&#xff0c;每次调整&#xff09; 时间复杂…

看后端程序员调试CORS的姿势

# 目录 为什么有同源策略&#xff1f; 需要解决的问题CORS跨域请求方案 preflightwithCredentials附&#xff1a;高效、优雅地调试CORS实现为什么有同源策略&#xff1f; 同源策略Same Origin Policy 是一种约定&#xff0c;是浏览器最核心的安全功能&#xff1a;该策略允许在…

堆的应用--并查集解决“擒贼先擒王”问题(JAVA)

现在有10个强盗。 1号强盗与2号强盗是同伙。 3号强盗与4号强盗是同伙。 5号强盗与2号强盗是同伙。 4号强盗与6号强盗是同伙。 2号强盗与6号强盗是同伙。 8号强盗与7号强盗是同伙。 9号强盗与7号强盗是同伙。 1号强盗与6号强盗是同伙。 2号强盗与4号强盗是同伙。 另外…

UVa 201 Square

这道题&#xff0c;没什么&#xff0c;就查找正方形&#xff0c; 特别注意一下 \n 的使用。 //UVa 201 //Square //#define LOCAL #include <stdio.h> #include <string.h> //use memset int dot[11][11][11][11], N;int getS(int size) {int cnt 0, flag;for(…

图论算法(四)--最小生成树的Kruskal [ 加边 ] 、Prim [ 加点 ] 的解法(JAVA)

之前我们介绍了求最短路径算法&#xff0c;现在又讲最小生成树算法&#xff0c;这两个算法有什么区别呢&#xff1f; 首先要明确&#xff0c;最短路径和最小生成树是两个不同的概念。 最短路径是对于一个图的两个结点而言的。在一个图中&#xff0c;结点A通过某些结点和边可以…

图论算法(五)--求解割点、割边(JAVA)

割点&#xff1a;对于一个连通图来说&#xff0c;如果删除某个点之后图不再连通&#xff0c;这个点就称为割点 割点算法 时间复杂度&#xff1a;O(NM) 但是下面给出的算法时间复杂度为O(N^2)&#xff0c;这是因为下面的存储结构都是邻接矩阵&#xff0c;这样的话用该算法就完…

express+handlebars 快速搭建网站前后台

最近在重构公司网站&#xff0c;原来网站使用PHP&#xff0c;前后端不分离&#xff0c;添加与更新网站内容仍使用原始方法&#xff0c;先出布局再把调好的布局给PHP后端开发&#xff0c;花时间长&#xff0c;维护不易。因此决定将网站前后端分离&#xff0c;核心功能含网站下单…

图论算法(六)-- 二分图的最大分配问题(JAVA)

二分图&#xff1a;又称二部图&#xff0c;如果一个图的所有顶点可以被分为X和Y两个集合&#xff0c;并且所有边的两个顶点恰好一个属于一个集合X&#xff0c;另一个属于集合Y&#xff0c;即每个集合内的顶点没有边相连&#xff0c;那么这个图就是二分图。 二分图的最大分配问…

定义一个二维数组并输入数据,将二维数组元素的值按升序排列,并输出排序后的二维数组。

目录 问题&#xff1a; 回顾&#xff1a; 给出两种做法&#xff1a; 解法一&#xff1a;调用qsort 函数进行排序 代码&#xff1a; 运行结果&#xff1a; 解法二&#xff1a;冒泡排序 代码&#xff1a; 运行结果: 回顾里的4种方法的模板参考&#xff1a; 1.冒泡排序…

.net core中使用GB2312编码

引用 System.Text.Encoding.CodePages 注册 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);转载于:https://www.cnblogs.com/liushunli/p/10342521.html

实验吧-密码学-杯酒人生(特殊凯撒--维吉尼亚密码)(凯撒加解密脚本、维吉尼亚密码加解密脚本)...

题目&#xff1a; 使用古典密码 一喵星人要想喵星发送一段不知道干什么用的密码“BLOCKCIPHERDESIGNPRINCIPLE”&#xff0c; 但是它忘记了密钥是什么&#xff0c; 手头&#xff08;爪头&#xff09;只有它自己加密过的密钥“HTRUZYJW”&#xff0c; 而且它 还知道原密钥是一个…

第五届省赛(软件类)真题----Java大学C组答案及解析

第五届省赛&#xff08;软件类&#xff09;真题—-Java大学C组答案及解析 杨辉三角调和级数回文素数过大年位平方和单位分数n级台阶 一、杨辉三角 二项式的系数规律&#xff0c;我国数学家很早就发现了。 如【图1.png】&#xff0c;我国南宋数学家杨辉1261年所著的《详解九…

Angular4.x 安装|创建项目|目录结构|创建组件

Angular4.x 安装|创建项目|目录结构|创建组件 安装最新版本的 nodejs node.js 官网&#xff1a;https://nodejs.org/zh-cn/ 去官网下载 node.js&#xff0c;下一步下一步就可以了。只要 node.js 安装成功&#xff0c;那么 npm 也会帮你安装完成&#xff01; 注意&#xff1a;请…

第五届省赛(软件类)真题----Java大学B组答案及解析

第五届省赛&#xff08;软件类&#xff09;真题—-Java大学B组答案及解析 正则切分调和级数n的n次幂七对数字勾股定理九阶数独G将军 一、正则切分 java中提供了对正则表达式的支持。 有的时候&#xff0c;恰当地使用正则&#xff0c;可以让我们的工作事半功倍&#xff01; …

第五届省赛(软件类)真题----Java大学A组答案及解析

第五届省赛&#xff08;软件类&#xff09;真题—-Java大学A组答案及解析 子序列最大长度莱布尼茨公式n的n次幂七对数字勾股定理九阶数独矩阵射线 一、子序列最大长度 一个串的子串是指该串的一个连续的局部。如果不要求连续&#xff0c;则可称为它的子序列。 比如对串&…

js获取一个月的天数

在使用其他语言获取每月天数的时候&#xff0c;一般都是存储到一个数组中进行获取&#xff0c;但是如果是二月份的话就需要首先判断是否闰年&#xff0c;再确定是28还是29了。 js可以通过Date对象很方便的获取到每月的天数&#xff0c;在初始化Date对象时&#xff0c;我们可以通…