经典算法之图的最短路径(二):Bellman_Ford算法
2015-09-02 15:22
429 查看
Bellman_Ford算法也是一个求图的最短路径的非常经典的算法,它适用于求单源最短路径,相比于同样用于单源最短路径的Dijkstra算法,它的适用范围更广,它可以用于有向图和无向图,并且权值可以为负,如果存在负权回路,可输出提示。
算法的流程就是:每次遍历图中所有边进行松弛(所谓的松弛是这样的——比如说存在一条边e(u,v),权值为w(u,v),如果d(v)>d(u)+w(u,v),则让d(v)=d(u)+w(u,v)),共遍历松弛V-1次(V是点的个数),此时如果不存在负权回路的话,d[i]就是源点到点i 的最短路径,因此再进行一次遍历,查看是否存在d(v)>d(u)+w(u,v),若存在,说明有负权值回路。下面上代码:(同样是偷懒没有正向打印路径)
算法的流程就是:每次遍历图中所有边进行松弛(所谓的松弛是这样的——比如说存在一条边e(u,v),权值为w(u,v),如果d(v)>d(u)+w(u,v),则让d(v)=d(u)+w(u,v)),共遍历松弛V-1次(V是点的个数),此时如果不存在负权回路的话,d[i]就是源点到点i 的最短路径,因此再进行一次遍历,查看是否存在d(v)>d(u)+w(u,v),若存在,说明有负权值回路。下面上代码:(同样是偷懒没有正向打印路径)
package classic; import java.util.Scanner; public class Bellman_Ford { static int start = 0, V = 0, E = 0; static int[][] G = null; static int[] d = null, pre = null; public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("输入点和边的数目:"); V = sc.nextInt();//总共有多少个点 E = sc.nextInt();//总共有多少个边 G = new int[V][V];//用来存放图的信息 d = new int[V];//用来存放从起点到每个点的最短路径长度 pre = new int[V];//用来存放每个点在其最短路径上的前一个结点 for(int x=0; x<V; x++){ for(int y=0; y<V; y++){ G[x][y] = Integer.MIN_VALUE; } } System.out.println("依次输入每条边的起点、终点和权值:(点的编号从0开始)"); for(int i=0; i<E; i++){//初始化图 int u = sc.nextInt(); int v = sc.nextInt(); int value = sc.nextInt(); G[u][v] = value; G[v][u] = value;//注意:假如为有向图,则不加这一行!! } for(int i=0; i<V; i++){//初始化d if(i==start) d[i] = 0; else d[i] = Integer.MAX_VALUE/2; } if(!bellman_ford()) System.out.println("图中存在负权值环"); else{//打印 for(int i=0; i<V; i++){ System.out.println("起点"+start+"到点"+i+"的最短路径长度为:"+d[i]); System.out.println("最短路径为:"); int curv = i; System.out.print(i+"<-"); while(true){ curv = pre[curv]; if(curv == start) break; System.out.print(curv+"<-"); } System.out.println(start); } } sc.close(); } static boolean bellman_ford(){ for(int i=1; i<V; i++){//对每条边都松弛V-1次 for(int x=0; x<V; x++){ for(int y=0; y<V; y++){ if(G[x][y]>Integer.MIN_VALUE){//说明有边 if(d[y]>d[x]+G[x][y]){ d[y] = d[x]+G[x][y]; pre[y] = x; } } } } } for(int x=0; x<V; x++){ for(int y=0; y<V; y++){ if(G[x][y]>Integer.MIN_VALUE){//说明有边 if(d[y]>d[x]+G[x][y]){ return false; } } } } return true; } }
相关文章推荐
- 动易2006序列号破解算法公布
- 渗透技术一瞥(图)
- 图片引发的溢出危机(图)
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- C++实现图的邻接矩阵存储和广度、深度优先遍历实例分析
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- C++实现图的邻接表存储和广度优先遍历实例分析
- 基于C++实现的各种内部排序算法汇总