图论算法(5) --- 双向广搜求最短路(Bidirectional Breadth First Search)

我们知道,在图论算法中,求最短路是最基本的问题。在求最短路的问题中,应用双向广度优先搜索算法,又是一个较为高效而又简单的算法。所谓双向广度优先搜索,其实根本的核心还是BFS,只不过它是从起点和终点两头同时搜索,大大提高了搜索效率,又节省了搜索空间。广搜大家知道当然是用队列来实现了,在这里,要注意的问题就是,我们必须按层搜索,正向队列处理一层,接着去处理反向队列的一层,按层交替进行,而不是按节点交替进行,这点需要注意,其他的也就很简单了,代码中附有注释,如有问题请留言。

package similarity;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

public class ShortestStep {
	Map<Integer, LinkedList<Integer>> graph;
	Map<String, Integer> graphmapping;

	public ShortestStep(String path) {//构造函数里初始化,构造无向图
		String[] strs;
		String str;
		int a, b;
		try {
			BufferedReader br = new BufferedReader(new FileReader(path));
			graph = new HashMap<Integer, LinkedList<Integer>>();
			while ((str = br.readLine()) != null) {
				strs = str.split("\\s");
				a = Integer.parseInt(strs[0]);
				b = Integer.parseInt(strs[1]);

				if (graph.containsKey(a)) {
					graph.get(a).add(b);
				} else {
					LinkedList<Integer> linkedlist = new LinkedList<Integer>();
					linkedlist.add(b);
					graph.put(a, linkedlist);
				}
				if (graph.containsKey(b)) {
					graph.get(b).add(a);
				} else {
					LinkedList<Integer> linkedlist = new LinkedList<Integer>();
					linkedlist.add(a);
					graph.put(b, linkedlist);
				}
			}
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public void initialMapping(String path) {/*此函数为备用,若想查询dbpedia数据集上URI之间的最短路,可用此初始化函数加载映射文件*/
		String[] strs;
		String str;
		graphmapping = new HashMap<String, Integer>();
		try {
			BufferedReader br = new BufferedReader(new FileReader(path));
			while ((str = br.readLine()) != null) {
				strs = str.split("\\s");
				int t = Integer.parseInt(strs[1]);
				graphmapping.put(strs[0], t);
			}
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public void findShortestStep(int a, int b) {/*双向广度优先搜索*/
		Queue<Integer> queue1 = new LinkedList<Integer>();//正向队列
		Queue<Integer> queue2 = new LinkedList<Integer>();//反向队列
		Queue<Integer> adj1;//记录邻接点
		Queue<Integer> adj2;
		Set<Integer> visit1 = new HashSet<Integer>();//标记是否访问
		Set<Integer> visit2 = new HashSet<Integer>();
		Map<Integer, Integer> step1 = new HashMap<Integer, Integer>();//记录步数
		Map<Integer, Integer> step2 = new HashMap<Integer, Integer>();
		queue1.add(a);
		queue2.add(b);
		visit1.add(a);
		visit2.add(b);
		step1.put(a, 0);
		step2.put(b, 0);
		int cnt1 = 0;//用来记录搜索的层数
		int cnt2 = 0;
		while (!queue1.isEmpty() || !queue2.isEmpty()) {
			while (true) {
				Integer nextnode1 = queue1.peek();
				adj1 = graph.get(nextnode1);
				if(step1.get(nextnode1)!=cnt1){
					//按层搜索,正向队列搜一层,反向队列搜一层,交替进行,
					//如果当前出队点的层数超过正在搜索的层数,则跳出循环,去反向队列搜索
					break;
				}
				queue1.poll();
				if (adj1 != null) {
					Iterator<Integer> itadj1 = adj1.iterator();
					while (itadj1.hasNext()) {
						Integer neighbor1 = itadj1.next();
						if (!visit1.contains(neighbor1)) {
							if (visit2.contains(neighbor1)) {//如果有共同的节点出现,则说明最短路找到,输出即可
								System.out.println(step2.get(neighbor1)
										+ step1.get(nextnode1) + 1);
								return;

							} else {
								queue1.add(neighbor1);
								visit1.add(neighbor1);
								step1.put(neighbor1, step1.get(nextnode1) + 1);

							}
						}
					}
				}
			}
			cnt1++;
			while (true) {
				Integer nextnode2 = queue2.peek();
				adj2 = graph.get(nextnode2);
				if(step2.get(nextnode2)!=cnt2){
					//按层搜索,正向队列搜一层,反向队列搜一层,交替进行,
					//如果当前出队点的层数超过正在搜索的层数,则跳出循环,去正向队列搜索
					break;
				}
				queue2.poll();
				if (adj2 != null) {
					Iterator<Integer> itadj2 = adj2.iterator();
					while (itadj2.hasNext()) {
						Integer neighbor2 = itadj2.next();
						if (!visit2.contains(neighbor2)) {
							if (visit1.contains(neighbor2)) {//如果有共同的节点出现,则说明最短路找到,输出即可
								System.out.println(step1.get(neighbor2)
										+ step2.get(nextnode2) + 1);
								return;

							} else {
								queue2.add(neighbor2);
								visit2.add(neighbor2);
								step2.put(neighbor2, step2.get(nextnode2) + 1);

							}
						}
					}
				}
			}
			cnt2++;
		}
	}

	public static void main(String[] args) {
		ShortestStep ss = new ShortestStep("c:/datatest.txt");
		ss.findShortestStep(6, 7);
	}
}
时间: 2024-10-10 05:25:33

图论算法(5) --- 双向广搜求最短路(Bidirectional Breadth First Search)的相关文章

图论算法》关于最大流转最短路两三事

又要来一篇高质量的博客了 这道题可以用BZOJ1001做例子, 首先我们来张图 这张图有6个点,10条边,每条边都有边权. 那么什么叫最大流最小割捏? 解释如下 在一个平面图中,能够从其实点到达终点的最大流量,等于,如果从网络中移除就能够导致网络流中断的边的集合的最小容量和. 那么这个问题如何转变为最短路问题捏 再来一张图 这张图和上图的区别就在于,我们新建了两条边,一条是从作为起源点的1向无限左建边,一条是从作为终止点的6向无限右建边. 我们又新建了7个点分别为0到6,每个点的定义为被原来的边

图论算法的数学模型

目录 图论算法的数学模型 引入:最短路的数学形式 最小割的数学形式 一些没用的总结 图论算法的数学模型 今天听敦敦敦的课总结一下... 前置芝士:网络流,最小割 引入:最短路的数学形式 松弛操作: 对于一条边\((u,v,w)\),\(\text {if}~(dis_u+w(u,v)<dis_v)~\text{then}~dis_v=dis_u+w(u,v)\) 所以对于求出来的dis,有\(dis_v\leq dis_u+w(u,v)\)对吧... 那么这和差分约束中\(x_i-x_j\leq

双向广搜的DIJKSTRA算法--简易的北京地铁导航实现

本学期的课程设计,实现最短路的算法,于是采用了DIJKSTRA算法,并用双向广搜优化了. 实现了简易的北京地铁导航.于是把代码分享出来. (核心代码是find_min(),Dijkstra()部分) 转载或者用到里面的代码请注明博主姓名以及出处! (注:只输入了图片里的地铁站信息,所用到的文件最下面有下载,因为这些文件是我和同学一条一条的录入的,所以如果你用到请务必注明这些文件的出处) 代码: /**************************************************

codevs 1225:八数码难题【双向广搜】

这里是传送门 这道题用普通BFS是可以做的,但是很明显没得过,效率太低了.效率更高的算法A*和双向广搜都可取,这写一下双向广搜的. 注意题目中的判重很重要,可以转化成九位数用hash来解决这个问题. #include <set> #include <string> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define

图论算法 有图有代码 万字总结 向前辈致敬

图的定义 背景知识 看到这篇博客相信一开始映入读者眼帘的就是下面这幅图了,这就是传说中的七桥问题(哥尼斯堡桥问题).在哥尼斯堡,普雷格尔河环绕着奈佛夫岛(图中的A岛).这条河将陆地分成了下面4个区域,该处还有着7座连接这些陆地的桥梁. 问题是如何从某地出发,依次沿着各个桥,必须经过每座桥且每座桥只能经过1次,最终回到原地. 不知道这个问题且好奇的童鞋现在肯定在忙活着找出来这道题的结果了. 是伟大的数学家欧拉(Leonhard Euler)在1736年首次使用图的方法解决了该问题. 欧拉将上面的模

nyoj 523 双向广搜

题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=523 #include<iostream> #include<cstdio> #include<queue> using namespace std; /* 用普通搜索TLE,已知起点和终点,可以考虑双向广搜或A*算法加速搜索 双向广搜,一个方向从出发点向终点搜索,一个方向从终点向出发点搜索,搜索到相同的结点时,即找到最短路径. */ const int N

图论算法之最短路径

图论算法之最短路径 作者:jasonkent27 转载请注明出处:www.cnblogs.com/jasonkent27 1. 前言 1.1 最短路引入 小明和小天现在住在海口(C1),他们俩计划暑假到三亚(C4)玩一趟,在海口和三亚之间有许多中间城市(文昌,临高,乐东,万宁...)图中的边上的数字是他们到达该城市必须的花费,现在需要你帮他们俩找出一条从海口到三亚的最省钱的路径出来. 等等,图中的边的weight怎么会有负的呢?你暂且可以这么理解吧.图中的边上的weight可以当作他们旅途中必须

基础图论算法导引

ACM中常用图论算法 1. 拓扑排序 -> 拓扑排序的原理及其实现 2. 最短路径算法 -> 最短路算法总结 差分约束系统 -> 差分约束 前k短路 -> 前K短路径问题 3. 最小生成树问题扩展 -> 最?小?生?成?树?问?题?的?拓?展  最优比率生成树 -> 最优比率生成树 最小k度限制生成树 -> IOI2004国家集训队论文,由汪汀所著(网盘内有) 或者刘汝佳的黑书内有 裸题 poj1639 题解 4. 二分图匹配 -> 二分图的最大匹配.完美匹

双向广搜 POJ 3126 Prime Path

POJ 3126  Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16204   Accepted: 9153 Description The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change th