双向广搜——DBFS

双向:简而言之就是从起点(正向搜索)和终点(逆向搜索)同时开始搜索,当两个搜索产生的一个子状态相同时就结束搜索。

通常有两种实现方法:

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

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

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

上例题(POJ 1915)

Description

Background
Mr Somurolov, fabulous chess-gamer indeed, asserts that no one else but him can move knights from one position to another so fast. Can you beat him?
The Problem
Your task is to write a program to calculate the minimum number of moves needed for a knight to reach one point from another, so that you have the chance to be faster than Somurolov.
For people not familiar with chess, the possible knight moves are shown in Figure 1.

                                                      

Input

The input begins with the number n of scenarios on a single line by itself.
Next follow n scenarios. Each scenario consists of three lines containing integer numbers. The first line specifies the length l of a side of the chess board (4 <= l <= 300). The entire board has size l * l. The second and third line contain pair of integers {0, ..., l-1}*{0, ..., l-1} specifying the starting and ending position of the knight on the board. The integers are separated by a single blank. You can assume that the positions are valid positions on the chess board of that scenario.

Output

For each scenario of the input you have to calculate the minimal amount of knight moves which are necessary to move from the starting point to the ending point. If starting point and ending point are equal,distance is zero. The distance must be written on a single line.

Sample Input

3
8
0 0
7 0
100
0 0
30 50
10
1 1
1 1

Sample Output

5
28
0

双向广搜很适合知道起点知道重点的问题~附代码:

#include<bits/stdc++.h>
using namespace std;
int dir[16]={1,2,-1,2,1,-2,-1,-2,2,1,2,-1,-2,1,-2,-1};   //搜索方向,这次用一维来存 
int n,m,xx[1000000],yy[1000000],vis[333][333],step[333][333];
int fx,fy,tx,ty;   //起点跟终点 
int dbfs(){
	int head=0,tail=0;   //模拟队列存搜索的点 
	memset(vis,0,sizeof(vis));
	memset(step,0,sizeof(step));
	xx[tail]=fx,yy[tail++]=fy,vis[fx][fy]=1;
	xx[tail]=tx,yy[tail++]=ty,vis[tx][ty]=2;
	while(head!=tail){   //当head==tail的时候 说明全部搜索完成 
		int x=xx[head],y=yy[head++];   //从队列出取出最前面的点 
		for(int i=0;i<16;){   //8个方向进行搜索 
			int dx=x+dir[i++],dy=y+dir[i++];
			if(dx<0||dx>=m||dy<0||dy>=m) continue;  //出了地图 排出去 
			if(vis[x][y]!=vis[dx][dy]&&vis[x][y]&&vis[dx][dy]) return step[x][y]+step[dx][dy]+1;   //遇到了,并且起点终点都搜到这里,第一次肯定是最优解 
			if(!vis[dx][dy]){    //存入队列,进行标记处理,起点到的标记为1,终点到的为2 
				vis[dx][dy]=vis[x][y];
				step[dx][dy]=step[x][y]+1;
				xx[tail]=dx,yy[tail++]=dy;
			}
		}
	}
	return 0;
}
int main(){
	cin>>n;
	while(n--){
		cin>>m;
		cin>>fx>>fy>>tx>>ty;
		cout<<dbfs()<<endl;
	}
	return 0;
}

老袋晕晕的~

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值