bellman-Ford查找输出一个负环(java)

Java 算法:Bellman-Ford算法 Bellman-Ford算法可以处理负权边。 如图所示,此时1到2存在一条负权边,且5+(-4)小于2,所以此时的最小路径为012,所以需要利用松弛操作来处理。 拥有负权环的图,没有最短路径。 前提:图中不能有负权环,Bellman-Ford算法可以判断图中是否有负权环,复杂度:O(EV) 第一次松弛操作: 第二松弛操作: 1.对一个点的一次松弛操作,就是找到经过这个点... 阅读详情

设一个加权有向图中有负权重的边,设图中存在若干负环,设计算法找出其中一个负环。

找负环考虑的是bellman-Ford算法,它是用来找最小生成树的算法,算法思想是循环|V-1|次,每次都对所有的边进行relax操作,最后再一次relax操作,如果还能被relax,就说明存在负环。

要找到负环,就从这条边的端点开始。

重要的具体实现代码:

  1:存储

  用hashMap存储邻接链表结构的图:pair里面存的是to顶点和权重。

	static HashMap<Integer, LinkedList<Pair<Integer, Integer>>> graph = new HashMap<>();//存储原始图
	static Scanner scanner = new Scanner(System.in);
	static int v, e;//顶点数,边数
	static int[] pre, dis, visted;//存储前节点和距离

2:初始化

初始化有一个要注意的就是dis数组初始化的时候不能用Integer.max_VALUE. 这样在执行relax的加法操作的时候会溢出,结果奇奇怪怪的。

public static void ini() {
		System.out.println("请输入顶点数:");
		v = scanner.nextInt();   
		
		System.out.println("请输入边数和各条边以及权重:");
		e = scanner.nextInt();
		
		pre = new int[v];
		dis = new int[v];

		for(int i=0; i<v; i++) {
			pre[i] = -1;
			dis[i] = 1000;//这里要注意
		}
				
		for(int i=0; i<e; i++) {
			graph.put(i, new LinkedList<>()); 
		}
		
		for(int i=0; i<e; i++)	{
			int from = scanner.nextInt();
			int to = scanner.nextInt();
			int weight = scanner.nextInt(); 
			graph.get(from).add(new Pair(to, weight));//有向图
			//graph.get(to).add(new Pair(from, weight));//双向添加
			//DFS(from, visited, graph);
		}
		printGraph(graph);
	}

3:relax(u,v)操作

如果v.d > u.d+w(u,v),更新v.d = u.d+w(u,v)。

public static void relax(int i, Pair<Integer, Integer> pair) { 
		int from = i, to = pair.getKey(), weight = pair.getValue();
		int newD = dis[from]+weight;
		if(dis[to] > newD) {
			dis[to] = newD;
			pre[to] = from; 
		}
	}

4:主要的bellman-Ford算法

public static void bellman_ford(HashMap<Integer, LinkedList<Pair<Integer, Integer>>> graph, int s) {
		
		dis[s] = 0;//源点到自己的距离是0;
		for(int i=0; i<v-1; i++) {
			for(int j=0; j<v; j++) {
				for(Pair<Integer, Integer> pair:graph.get(j)) {//每一个点的linkedList
					relax(j, pair);
				}
			}
		} 
		
		//验证有无负环
			for(int j=0; j<v; j++) {
				for(Pair<Integer, Integer> pair:graph.get(j)) {//每一个点的linkedList
					if(dis[pair.getKey()] > dis[j]+pair.getValue()) {//
						findCir(pair.getKey());				
						System.exit(0);
					}
				}
			} 
	}

5:根据找到的可以relax的边,找出负环

//根据点找负环,一直找pre,直到找到跟起点重合,则为一个负环
	public static void findCir(int u) {

		List<Integer> res = new LinkedList<>();
		int end = pre[u]; 
		//System.out.println(u+" ");
		
		for(int a:pre)
			System.out.print(a+" ");
		
		while(true) { 
			if(end==-1)
				continue;
			
			if(res.indexOf(end)!=-1)//查找到了
				break;
			res.add(end);
			end = pre[end];
		}
		 
		if(res.size()>0) {
			System.out.println("图中存在负环:");
			for(int i=0; i<res.size(); i++)
				System.out.print(res.get(i)+"-> ");
		} else
			System.out.println("图中没有负环"); 
		
	}

 

至此结束。

可以优化的地方:可以在bellman-Ford最后那个relax的地方做个操作,不让其终止,而是继续,这样可以找出所有的负环。

 

我总觉得这个算法是存在问题的,一时又找不出哪里有毛病,望看到的不吝赐教。

附带源码:

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

import javax.swing.text.html.HTMLDocument.HTMLReader.PreAction;

import javafx.util.Pair;
import sun.awt.image.ImageWatched.Link;

public class test4 {

	static HashMap<Integer, LinkedList<Pair<Integer, Integer>>> graph = new HashMap<>();//存储原始图
	static Scanner scanner = new Scanner(System.in);
	static int v, e;//顶点数,边数
	static int[] pre, dis, visted;//存储前节点和距离
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void ini() {
		System.out.println("请输入顶点数:");
		v = scanner.nextInt();   
		
		System.out.println("请输入边数和各条边以及权重:");
		e = scanner.nextInt();
		
		pre = new int[v];
		dis = new int[v];

		for(int i=0; i<v; i++) {
			pre[i] = -1;
			dis[i] = 1000;
		}
				
		for(int i=0; i<e; i++) {
			graph.put(i, new LinkedList<>()); 
		}
		
		for(int i=0; i<e; i++)	{
			int from = scanner.nextInt();
			int to = scanner.nextInt();
			int weight = scanner.nextInt(); 
			graph.get(from).add(new Pair(to, weight));//有向图
			//graph.get(to).add(new Pair(from, weight));//双向添加
			//DFS(from, visited, graph);
		}
		printGraph(graph);
	}
	
	//输出图
	public static void printGraph(HashMap<Integer, LinkedList<Pair<Integer, Integer>>> graph) {
		for(int i=0; i<v; i++) {
			System.out.print("\n"+i+" : ");
			for(Pair<Integer, Integer> p : graph.get(i)) {
				System.out.print("  "+i+"->"+p.getKey()+" "+p.getValue());//i->p 3
			}
		}
		System.out.println();;
	}
	
	//relax操作
	public static void relax(int i, Pair<Integer, Integer> pair) { 
		int from = i, to = pair.getKey(), weight = pair.getValue();
		int newD = dis[from]+weight;
		if(dis[to] > newD) {
			dis[to] = newD;
			pre[to] = from; 
		}
	}

	//beelman-ford
	public static void bellman_ford(HashMap<Integer, LinkedList<Pair<Integer, Integer>>> graph, int s) {
		
		dis[s] = 0;//源点到自己的距离是0;
		for(int i=0; i<v-1; i++) {
			for(int j=0; j<v; j++) {
				for(Pair<Integer, Integer> pair:graph.get(j)) {//每一个点的linkedList
					relax(j, pair);
				}
			}
		} 
		
		//验证有无负环
			for(int j=0; j<v; j++) {
				for(Pair<Integer, Integer> pair:graph.get(j)) {//每一个点的linkedList
					if(dis[pair.getKey()] > dis[j]+pair.getValue()) {//
						findCir(pair.getKey());				
						System.exit(0);
					}
				}
			} 
	}
	
	//根据点找负环,一直找pre,直到找到跟起点重合,则为一个负环
	public static void findCir(int u) {

		List<Integer> res = new LinkedList<>();
		int end = pre[u]; 
		//System.out.println(u+" ");
		
		for(int a:pre)
			System.out.print(a+" ");
		
		while(true) { 
			if(end==-1)
				continue;
			
			if(res.indexOf(end)!=-1)//查找到了
				break;
			res.add(end);
			end = pre[end];
		}
		 
		if(res.size()>0) {
			System.out.println("图中存在负环:");
			for(int i=0; i<res.size(); i++)
				System.out.print(res.get(i)+"-> ");
		} else
			System.out.println("图中没有负环"); 
		
	}
	
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ini();//初始化
		bellman_ford(graph, 0);
}
 

 

负权值最短路径Bellman-Ford算法 最短路径算法、负权值 阅读详情

相关推荐

算法之Bellman - Ford算法:从图的路径到套汇交易的深度探索

大家好!在算法学习的漫漫长路上,每一次新的发现都像是点亮了一盏明灯,照亮我们前行的方向。我一直希望能和大家一同分享这些学习的收获,在交流中共同进步。今天,咱们就来深入探究一个非常实用且有趣的算法——Bellman - Ford算法,看看它如何解决复杂图的最短路径问题,甚至还能应用到金融交易领域。

wj_rdk的博客 1553

spfa算法求负环

 传送门:P3305[模板]负环 负环的定义是:一条边权之和为负数的回路。 一个含有负环的图是一定没有最短路的,因为一旦有负环则在求最短路的时候回陷在负环中而无法自拔。  所以,若图中没有负环,则最多经过n-1轮迭代后算法结束。若第n轮迭代仍有结点的最短路能被更新,则图中有负环。  所以我们用 cnt[x] 表示1到x的最短路包含的边数(该题要求以1作为源点),cnt[1]=0。每次用 dis[x]+w(x,y) 更新dis[y]时,也是cnt[x]+1更新 cnt[y]。此过程中若出现cnt[y]≥n,则

Lucas_FC_的博客 606

深入解析Bellman Ford's Algorithm,高效解决含有负权重图中的最短路径问题

概述 Bellman Ford算法可以用来解决加权图中的最短路径问题。其与Dijkstra算法的区别在于Belllman Ford算法的应用范围更广,例如其可以用来处理带有负权重的加权图中的最短路径问题。由于Dijkstra算法本质上是一种贪心算法,因而当图中存在路径权值之和为负的环时,Dijkstra算法会给出错误的结果因为其总是偏向于选择当前情况下的局部最优路径。Bellman Ford算法的...

正西风落叶下长安 2641

Bellman-Ford-贝尔曼-福特-算法求最短路-负环

Bellman-Ford-贝尔曼-福特-算法求最短路-负环

重生之我是cxk的博客 815

Bellman–Ford算法原理适用场景原则python java示例详解

[Bellman–Ford算法原理适用场景原则python java示例详解--点击这里可看全文](https://zhuanlan.zhihu.com/p/679211338)

wang2leee的博客 1166

算法之Bellman - Ford算法:复杂图最短路径的破局者

在算法的学习旅程中,每一个新的算法都是一次挑战与机遇。我一直希望能和大家一同探索算法的奇妙世界,在这个过程中共同成长、共同进步。今天,我们将深入研究一个在处理复杂加权有向图最短路径问题时极为关键的算法——Bellman - Ford算法。它能够应对包含负权重边甚至负权重环(在特定条件下)的复杂图,掌握它对我们理解图算法和解决实际问题有着重要意义。

wj_rdk的博客 1243

bellman-ford算法、spfa算法求带负环的最短路、差分约束

一、bellman-ford算法求最短路 Bellman-ford适用范围:单源最短路径(找给定源点到其他点的最短距离),图中边的权重可为负数即负权边,但不可以出现负权环。时间复杂度是O(nm) const int N = 1e4 + 10; const int inf = 0x3f3f3f3f; int n, m, k;//点数,边数,可以使用的最大边数 int back1[N];//防止某个点的最短边更新两次 int dist[N];//标记从1-n的最短路径长度 struct node{ i

m0_52223599的博客 2087

Bellman-Ford算法详解与Java实现:含负权重边的最短路径求解

简单来说,松弛就是一次“如果这样会不会更好?”的试探。对于任意一条从顶点 $ u $ 到 $ v $ 的边 $ (u, v) $,如果我们当前认为到 $ v $ 的最短距离是d[v],但通过 $ u $ 再走一步过去反而更近(即),那我们就该更新对 $ v $ 的认知。数学表达如下:$$$$这本质上是对三角不等式的一次验证。在理想状态下,任何两点间的直接路径都不应比绕道其他节点更长。一旦发现违反,说明还有优化空间。来看一个直观的例子:| ^

weixin_42612804的博客 739

Bellman-Ford算法判负环

算法思想:如果没有负权回路,dis数组应该会在n-1次松弛之后结束。 算法复杂度:O(n*m)。比Dijkstra算法复杂度要高。 代码: bool Bellman_Ford(int s) { int i,j,k; for(i=0;i<=n;i++) dis[i] = Mod; dis[s] = 0; for...

weixin_30402343的博客 149

AURIX™ TC49x芯片手册中文分享(二)

主要内容为第一章、功能模块的特征

xibaofenqi的博客 1562

ADS2019学习笔记:三、SPICE model导入

以BZX84-C33 SPICE model为例,学习如何在ADS2019中导入SPICE model。

qq_42945911的博客 6492

算法设计与分析第二次编程作业 1232. 负环

题目描述 给定一个大小为nnn的有向图GGG,判断其是否有负环。 输入格式 第一行两个整数nnn和mmm分别表示图GGG的点数和边数。 接下来mmm行,每行三个整数x,yx,yx,y和zzz,表示xxx到yyy有一条权值为zzz的边。 输出格式 如果有负环则输出"Yes",否则输出"No"。(不包括双引号) 样例输入 4 4 2 1 4 2 3 2 3 4 2 4 2 -8 样例输出 Yes 数据范围 对于100%的数据,n≤3000,m≤5000n \le 30

zhiyuan5986的博客 233

电磁波成像技术全解析:从γ射线到无线电波的应用实践

本文全面解析电磁波成像技术,从γ射线到无线电波的应用实践。详细介绍了不同波长电磁波的特性与实用场景,包括医疗影像、工业检测、安防监控等领域。特别探讨了X射线、红外热成像、毫米波雷达等前沿技术的实战应用,为读者提供技术选型指南和操作技巧。

weixin_29305337的博客 292

【最短路算法】第二弹:一文弄懂Bellman-Ford(贝尔曼福特算法)

【最短路算法】一篇文章彻底弄懂Dijkstra算法|多图解+代码详解Dijstra算法用于计算单源正权边的最短路问题今天学习的贝尔曼福特算法,是用于计算单源,且可含负权边的最短路问题用于求解单源、有负权边的最短路问题实现通过m次迭代求出从起点到终点不超过m条边构成的最短路径其优于Dijkstra的方面是边的权值可以为负数、实现简单,缺点是时间复杂度过高。

Yaoyao2024的博客 2万+

通俗理解Xgboost

为了简化计算,XGBoost采用了一阶导数(梯度)和二阶导数(Hessian)来近似损失函数的变化,从而推导出叶子节点值的更新公式。其中 z 就是所有树的叶子节点分数之和。通过这两个正则化项,XGBoost能够在优化目标函数时,不仅考虑损失函数的最小化,还考虑了模型的复杂度,从而达到更好的泛化性能。正则化项通常包括两个部分:一个是与叶子节点数量相关的项,另一个是与叶子节点输出值大小相关的项。通过这种方式,XGBoost能够有效地计算出每个叶子节点的值,同时通过正则化项来平衡模型的复杂度和泛化能力。

金融风控笔记 750

YOLOv8改进---BiFPN特征融合

yolov8结合BiFPN进行改进

qq_41920323的博客 4523

数据结构与算法 - Bellman-Ford算法:处理负权边的最短路径问题

本文介绍了Bellman-Ford算法,这是一种用于解决单源最短路径问题的动态规划算法,特别适用于包含负权重边的图。文章首先通过类比说明算法原理,随后回顾了图论基本概念,详细阐述了算法的核心思想——通过V-1次松弛操作逐步逼近最优解。通过具体示例分步演示了算法执行过程,分析了算法复杂度为O(V×E),并提供了Python代码实现。与Dijkstra算法相比,Bellman-Ford虽然效率较低,但能处理负权边情况,是图论中重要的基础算法之一。

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

Python画柱状图(双柱状图,三柱状图)且显示对应数值

使用python实现双柱状图和三柱状图,并且在柱状图形的顶部显示对应数值;

yue200403的博客 1万+

Bellman Ford算法:解决负权边图的最短路径问题

Bellman Ford算法,就像是我们的导游,帮助我们在这个复杂的城市中找到了方向。它不仅可以处理有负权边的图,还可以检测到负权重环,避免我们陷入无限循环的困境。这是它相比其他图算法的一个重要优势。然而,Bellman Ford算法并不是万能的。它的时间复杂度为O(VE),在处理大规模图时可能效率不高。而且,它只能解决单源最短路径问题,不能解决多源最短路径问题。这些都是我们需要考虑的问题。

万猫学社 1675

系统架构最佳实践 -- 统一身份认证系统

设计和实现一个高效、安全的统一身份认证系统需要考虑到系统架构设计、用户认证与授权、用户身份管理、安全性保障、日志记录与审计、高可用性与容错性,以及用户体验优化等多个方面。通过合理的架构设计、安全措施和用户体验优化,可以构建一个满足用户需求、提供安全可靠的身份认证服务的系统。本文将总结统一身份认证系统的架构设计与实践经验,帮助读者了解如何设计和实现一个高效、安全的统一身份认证系统。统一身份认证系统应支持详细的日志记录和审计功能。通过合理的身份认证策略和授权机制,可以确保用户身份的准确性和信息的安全性。

xiaoli8748的专栏 1704

YOLOv11 改进策略之 Conv 篇:基于 C2fC 与 RepC_SPELAN4 的性能跃迁教程

某工业质检场景中,采用本文改进模块的 YOLOv11 模型,对微小零件缺陷的检测准确率提升 22%;YOLOv10 提出的 C2fC 模块与 RepC_SPELAN4 结构,是针对特征融合与卷积效率的突破性设计,掌握它们,你就能让自己的 YOLOv11 模型在精度与速度的平衡上实现“质的飞跃”。别再让“模型精度不足”成为你的瓶颈——现在就动手修改代码,让你的 YOLOv11 模型在特征提取与检测效率上实现质的飞跃,用技术实力证明你的 AI 研发能力!中的卷积层为 RepC_SPELAN4。

m0_71589036的博客 97

数据结构与算法 - 负环检测:Bellman-Ford与Floyd算法的应用

本文探讨了图论中负环检测的关键算法——Bellman-Ford和Floyd算法。负环指图中权重和为负的环路,会导致最短路径问题无解。Bellman-Ford通过V-1次松弛操作检测可达负环,时间复杂度O(VE);而Floyd算法通过三重循环检测所有顶点间的负环,时间复杂度O(V³)。文章详细解析了算法原理、实现代码和应用场景,并对比了两者的优劣:Bellman-Ford适合稀疏图和单源检测,Floyd适用于稠密图和全源检测。最后指出正确选择算法需考虑图结构特点和具体需求。

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Bellman-Ford算法--解决负权边问题

前阵子备考蓝桥杯的时候碰到了这个算法,感觉还挺有意思的,实现起来也非常简单。贝尔曼-福特算法(Bellman-Ford)是由理查德·贝尔曼(Richard Bellman) 和 莱斯特·福特 创立的,求解单源最短路径问题的一种算法。有时候这种算法也被称为 Moore-Bellman-Ford 算法,因为 Edward F. Moore 也为这个算法的发展做出了贡献。它的原理是对图进行V-1次松弛操作,得到所有可能的最短路径。其优于迪科斯彻算法。

冲出仁川,走出马德里,故事还会再继续 2067

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【图论】C006_洛谷模板题:负环(SPFA / Bellman-Ford / 链式向前星)

一、题目描述 寻找一个从顶点 1 所能到达的负环,负环定义为:一个边权之和为负的环。 输入格式 本题有多组数据 第一行一个正整数 TT 表示数据组数,对于每组数据: 第一行两个正整数 N,M,表示图有 N 个顶点,M 条边 接下来 MM 行,每行三个整数 a, b, wa,b,w,表示a \rightarrow ba→b 有一条权值为 ww 的边(若 w<0w<0 则为单向,否则双...

无敌兔0x01 600

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

[Java学习] 最短路径计算——Bellman_Ford算法

文章目录前言一、Dijstra算法局限性二、Bellman_Ford算法1.算法介绍2.具体例子分析 前言 上篇文章写到Dijstra算法。但是在有些情况下,比如有负权边时,Dijstra算法就不能再使用了,因此需要一个新的算法来解决这个问题。 对于存在负权边的问题,有两种算法:Bellman_Ford算法和SPFA算法,本篇博客主要介绍一些Bellman_Ford算法。 一、Dijstra算法局限性 1.问题:为什么Dijstra不能运用在含负权边的图中? 比如下面这个例子: 利用Dijstra算.

Admzy的博客 1507

HandBrake 视频锐化实操:Unsharp 与 Laplacian 各管什么,参数怎么起步

转码后画面发软、放大看全是肉,是 HandBrake 用户最常碰到的清晰度问题。很多人会把界面上的 Sharpen 选项直接拉满,结果噪点被一起放大,边缘还挂了一圈白边。HandBrake 里和"锐化"沾边的东西其实分两类:一类是真正负责增强的 Unsharp 滤镜,另一类是藏在 decomb 滤镜里、用 Laplacian 算子做边缘判定的阈值参数。这篇文章帮你分清两者边界,并给出可以直接上手的

gitblog_00643的博客 343
上一篇: 用局部替换方式求解最小生成树 java
下一篇: 加权有向完全图中找最小TSP圈
monkey1008611
博客等级 码龄10年 14粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值