POJ 1915(双向广搜)

应该是双向广搜的简单题,虽然写了很久。双向:简而言之就是从起点(正向搜索)和终点(逆向搜索)同时开始搜索,当两个搜索产生的一个子状态相同时就结束搜索。

通常有两种实现方法:

1、用一个队列来储存子状态,起点和终点先后入队,正向搜索和逆向搜索交替进行,两个方向的搜索交替扩展子状态。直到两个方向的搜索产生相同的子状态结束。

2、两个方向的搜索虽然是交替扩展子状态的。但是两个方向生成的子状态的速度不一定平衡。所以,可以每次选择子状态数较少的那个方向先进行扩展。这样就不会出现两个方向生成子状态的速度的不平衡,可以明显的提高效率哦。

这里只给出用第一种方法实现的代码。因为双向广搜要判断两个方向搜索产生的子状态是否相同,所以要用到标记数组和记录结果的数组一个或两个任选,这里用的是一个数组来标记,正向标记为1,逆向标记为2,0表示未访问。

/**
**author :Skylon **
╭︿︿︿╮
{/ A  C /}
 ( (OO) )
  ︶︶︶
**    **
**POJ_1915题**
** 2014 年 7月 19日**
**/
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cctype>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define maxM 310
#define maxN 1000000
using namespace std;
int n,sx,sy,ex,ey;//图的大小,起点,终点
int dir[16]={1,2,-1,2,1,-2,-1,-2,2,1,2,-1,-2,1,-2,-1};//搜索的方向,用一维素组来存储的,每相邻的两个数表示一个搜索方向,16/2个方向。注意循环时的下标处理。
int xx[maxN],yy[maxN];//数组模拟队列
int vis[maxM][maxM],step[maxM][maxM];//vis为标记,step为结果
int fun()
{
	memset(step,0,sizeof(step));
	memset(vis,0,sizeof(vis));
	int head=0,tail=0;//初始化头尾指针
	xx[tail]=sx,yy[tail++]=sy,vis[sx][sy]=1;//起点入队,并标记为1,正向搜索
	xx[tail]=ex,yy[tail++]=ey,vis[ex][ey]=2;//终点入队,并标记为2,逆向搜索
	while (head!=tail)
	{
		int x=xx[head],y=yy[head++],t=step[x][y];//x、y取队首。head++,出队。t记录此时的步数
		for (int i=0;i<16;)//16/2个方向搜索
		{
			int l=x+dir[i++],r=y+dir[i++];
			if (r<0||r>=n||l<0||l>=n)//边界判断
				continue ;
			if (vis[x][y]!=vis[l][r]&&vis[x][y]&&vis[l][r])//当正向搜索和逆向搜索产生的子状态相同时,结束搜索
				return step[l][r]+step[x][y]+1;//返回正向搜索的步数+逆向搜索的步数+搜索到该相同子状态的步数
			if (!vis[l][r])//如果没有达到该状态,则继续入队。不能用if(vis[l][r]==0)因为vis标记的是正向和逆向两个状态
			{
				xx[tail]=l,yy[tail++]=r;//入队
				step[l][r]=t+1;//记录步数
				vis[l][r]=vis[x][y];//标记,将前一个状态的值赋给当前状态,而不是用1、2赋值,就能保证正向搜索产生子状态被标记为正向;逆向搜索产生的子状态被标记为逆向
			}
		}
	}
	return 0;//起点和终点相同
}
int main()
{
	int t;
	scanf("%d",&t);
	while (t--&&scanf("%d%d%d%d%d",&n,&sx,&sy,&ex,&ey))
		printf("%d\n",fun());
	return 0;
}
时间: 2024-12-24 08:18:56

POJ 1915(双向广搜)的相关文章

双向广搜 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

poj 1915 双向 BFS 利用数组 a[x][y] = a[cp.x][cp.y] + 1; b[x][y] = b[cp.x][cp.y] + 1;保留步数

#include<iostream>#include<queue> using namespace std; struct point{    int x, y;};point bufa[8] ={    {-2, 1}, {-1, 2}, {1, 2}, {2, 1},    {2, -1}, {1, -2}, {-1, -2}, {-2, -1}}; int n, a[305][305], b[305][305]; int rule(int x,int y)//判断是否符合棋盘

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

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

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

HDU 3085 Nightmare Ⅱ (双向广搜)

题意:有M,G两人和鬼魂(Z)在n*m的方格内,M每秒走3步,G每秒走一步,鬼魂每秒走2步,问是否能 不遇到鬼魂下两人相遇,鬼魂可以穿墙(X),人不可以.初始鬼魂有2个. #include<stdio.h> #include<string.h> #include<string> #include<queue> #include<map> #include<iostream> #include<algorithm> #def

双向广搜 开始!!!

先简单的了解一下,双向广搜很好理解,就是从两端一起搜,如果遇到之前已经搜到过的状态,就相当于已经有解了,这样就会节省一半的内存和时间,并且代码复杂度并不高.只需要在正常的基础上多开一个域,保存这个点是从起始状态还是终止状态拓展的.当然双向广搜中状态的判断需要一些技巧,现在还没有总结出什么. 八数码问题: 很经典的一种双向广搜,因为只有九个数,所以用康托展开作为hash值.拓展时,如果这个hash值已经访问过,就判断,如果是两条路过来的就输出,否则就继续做:对于没有访问过的hash值就可以添加到队

双向广搜

双向广搜 (2011-08-31 16:45:24)   Eight    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 讲到双向广搜,那就不能不讲经典的八数码问题,有人说不做此题人生不完整 . 所谓双向广搜,就是初始结点向目标结点和目标结点向初始结点同时扩展,直至在两个扩展方向上出现同一个结点,搜索结束.它适用的问题是,扩展结点较多,而目标结点又处在深沉,如果采用单纯的广搜解题,搜索量巨大,搜索速度慢是可想而知的,同时往往也会出现内存空

双向广搜 codevs 3060 抓住那头奶牛

codevs 3060 抓住那头奶牛 USACO 时间限制: 1 s 空间限制: 16000 KB 题目等级 : 黄金 Gold 题目描述 Description 农夫约翰被告知一头逃跑奶牛的位置,想要立即抓住它,他开始在数轴的N 点(0≤N≤100000),奶牛在同一个数轴的K 点(0≤K≤100000).约翰有两种移动方式:1 分钟内从x 点移动到x+1 或x-1:1 分钟内从x 点移动到2x.假设奶牛不会移动,约翰抓住它需要多少时间? 输入描述 Input Description 一行两个

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

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