POJ 3083 - 变向DFS + BFS

1.Question:

本题是一道非常好的搜索题,号不是好在本题混合了深搜和广搜,而是好在了本题的新的思路
首先,题意:
有一个迷宫,我们现在要求出在各种限制下的从S走到E的步数
首先题目限制了一定有解存在

1.我们现在定义初始方向,题目中明确说明了(我没有看到,半天没有理解题意),我们定义S的状态只有这么几种情况
S不会出现在地图的中间,S不会出现在地图的四个角落,S只会在地图的四条边上,我们现在声明S的初始方向就是S邻近的边的反方向

2.题目中第一个要求的限制就是,现在我们的移动策略是左转优先,也就是当前的方向的顺时针方向转动
题目中的第二个要求的限制就是,现在我们的移动策略是右转优先,也就是当前的方向的逆时针方向转动
题目中的第三个要求的限制就是,要求我们求出从S到E的最短路径,这个第三个是最好求得一个,简简单单的BFS就可以搞定
所以说我们的难点在于求有优先的第一和第二要求了,也就是变向的DFS

2.Solution:

在这里我们会注意到,因为出现了左右转优先的定义,实际上,本题的难点不在于DFS本身,而在于DFS的变换方向的特性(这正是因为我们的左右转的优先引起的)
但是在这里我们解决问题的思路有两点需要注意:
1.不能标记:
根据我们题目的样例来看,我们左右转优先的步数是按照找到E的最终的步数来统计的,也就是说,本题中我们是允许走回头路的(但是回头路始终是最后一个需要考虑的走的方向,无论是顺时针还是逆时针),所以,很显然,我们这里就不能标记方向了
但是我们处理的思路很奇妙,既然回头路是最后一个走的,说明走回头路的时候,其他的三个方向都行不通,也就是说,我们走到了死胡同,但是我们也不仅仅是走到了死胡同的时候才会走回头路(这一点自己体会,这里不好描述)
所以我们只要确定好了顺序的话其实是不不会出现无限循环的情况的,这一点我们即将解决
2.变向:
变向的处理,我们引入一个参数叫做"当前的方向"
我们怎么定义当前的方向都好,这里我给出我的参考:
    4
3  0  1
    2
这里的0代表当前的位置,3,4,1,2分别是我们的方向坐标系,在左转右转的条件下,我们的坐标系的转化就好写了
定义当前的格子:
    2
1  N  3
    4
左转条件下的变换:
方向4:1 2 3 4
方向3:4 1 2 3
方向2:3 4 1 2
方向1:2 3 4 1
右转条件下的变换:
方向4:3 2 1 4
方向3:2 1 4 3
方向2:1 4 3 2
方向1:4 3 2 1
以上,我们根据不同的转换规则写我们的move转移数组就好了

3.Code:

/*
Problem: 3083		User: *************
Memory: 728K		Time: 16MS
Language: G++		Result: Accepted
*/
#include"iostream"
#include"cstdio"
#include"cstring"
#include"cstdlib"

using namespace std;

typedef struct node
{
	int x;
	int y;
	int step;
}point;

int x,y;
char map[45][45];
bool book[45][45];  //bfs
int move_1[4][4][2]=    //map[0] - 1,map[1]-2   map[2]-3   map[3]-4 左偏向 
{
    {{-1,0},{0,1},{1,0},{0,-1}},
    {{0,1},{1,0},{0,-1},{-1,0}},
    {{1,0},{0,-1},{-1,0},{0,1}},
    {{0,-1},{-1,0},{0,1},{1,0}}
};
int move_2[4][4][2]=   //右偏向 
{
	{{1,0},{0,1},{-1,0},{0,-1}},
    {{0,-1},{1,0},{0,1},{-1,0}},
    {{-1,0},{0,-1},{1,0},{0,1}},
    {{0,1},{-1,0},{0,-1},{1,0}}
};
int bx,by,ex,ey;
int left_;
int right_;
int minp;
int pre_dir;
bool bl;
bool br;

void dfs_left(int dx,int dy,int atom,int time)
{
	int px,py;
	for(int i=0;i<4;i++)
	{
		px=dx+move_1[atom-1][i][0];
		py=dy+move_1[atom-1][i][1];
		if(px==ex&&py==ey) 
		{
			left_=time+1;
			bl=true;
			return ;
		}
		if(map[px][py]=='#'||px<1||px>x||py<1||py>y) continue;
		else
		{
			if(atom==4)
			{
				if(i==0) dfs_left(px,py,3,time+1);
				else if(i==1) dfs_left(px,py,4,time+1);
				else if(i==2) dfs_left(px,py,1,time+1);
				else dfs_left(px,py,2,time+1);
			}
			else if(atom==3)
			{
				if(i==0) dfs_left(px,py,2,time+1);
				else if(i==1) dfs_left(px,py,3,time+1);
				else if(i==2) dfs_left(px,py,4,time+1);
				else dfs_left(px,py,1,time+1);
			}
			else if(atom==2)
			{
				if(i==0) dfs_left(px,py,1,time+1);
				else if(i==1) dfs_left(px,py,2,time+1);
				else if(i==2) dfs_left(px,py,3,time+1);
				else dfs_left(px,py,4,time+1);
			}
			else
			{
				if(i==0) dfs_left(px,py,4,time+1);
				else if(i==1) dfs_left(px,py,1,time+1);
				else if(i==2) dfs_left(px,py,2,time+1);
				else dfs_left(px,py,3,time+1);
			}
			if(bl) return ;
		}
	}
}

void dfs_right(int dx,int dy,int atom,int time)
{
	int px,py;
	for(int i=0;i<4;i++)
	{
		px=dx+move_2[atom-1][i][0];
		py=dy+move_2[atom-1][i][1];
		if(px==ex&&py==ey) 
		{
			right_=time+1;
			br=true;
			return ;
		}
		if(map[px][py]=='#'||px<1||px>x||py<1||py>y) continue;
		else
		{
			if(atom==4)
			{
				if(i==0) dfs_right(px,py,1,time+1);
				else if(i==1) dfs_right(px,py,4,time+1);
				else if(i==2) dfs_right(px,py,3,time+1);
				else dfs_right(px,py,2,time+1);
			}
			else if(atom==3)
			{
				if(i==0) dfs_right(px,py,4,time+1);
				else if(i==1) dfs_right(px,py,3,time+1);
				else if(i==2) dfs_right(px,py,2,time+1);
				else dfs_right(px,py,1,time+1);
			}
			else if(atom==2)
			{
				if(i==0) dfs_right(px,py,3,time+1);
				else if(i==1) dfs_right(px,py,2,time+1);
				else if(i==2) dfs_right(px,py,1,time+1);
				else dfs_right(px,py,4,time+1);
			}
			else
			{
				if(i==0) dfs_right(px,py,2,time+1);
				else if(i==1) dfs_right(px,py,1,time+1);
				else if(i==2) dfs_right(px,py,4,time+1);
				else dfs_right(px,py,3,time+1);
			}
			if(br) return ;
		}
	}
}

void bfs()
{
	memset(book,0,sizeof(book));
	int nn[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
	point queue[41*41];
	int head=1;
	int tail=2;
	queue[1].x=bx;
	queue[1].y=by;
	queue[1].step=1;
	book[bx][by]=true;
	while(head!=tail)
	{
		for(int i=0;i<4;i++)
		{
			int dx=queue[head].x+nn[i][0];
			int dy=queue[head].y+nn[i][1];
			if(map[dx][dy]=='E')
			{
				minp=queue[head].step+1;
				return ;
			}
			if(dx<1||dx>x||dy<1||dy>y||map[dx][dy]=='#'||book[dx][dy]) continue;
			else
			{
				book[dx][dy]=true;
				queue[tail].x=dx;
				queue[tail].y=dy;
				queue[tail].step=queue[head].step+1;
				tail++;
			}
		}
		head++;
	}
}

int main()
{
	int t;
	scanf("%d",&t);getchar();
	while(t--)
	{ 
	    bl=br=false;
		minp=left_=right_=1;  //刚开始S也算 
		scanf("%d%d",&y,&x);getchar();
		for(int i=1;i<=x;i++)
		{
			for(int j=1;j<=y;j++)
			{
				scanf("%c",&map[i][j]);
				if(map[i][j]=='S') 
				{
					bx=i,by=j;
					if(i==1) pre_dir=2;
					else if(i==x) pre_dir=4;
					else if(j==1) pre_dir=1;
					else if(j==y) pre_dir=3; 
				}
				if(map[i][j]=='E') ex=i,ey=j;
			}
			getchar();
		}
		dfs_left(bx,by,pre_dir,1);
		dfs_right(bx,by,pre_dir,1);
		bfs();
		printf("%d %d %d\n",left_,right_,minp);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值