DFS—POJ3083-Children of the Candy Corn

题目POJ3083大意:

给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走

先输出左转优先时,从S到E的步数

再输出右转优先时,从S到E的步数

最后输出S到E的最短步数

 

W为宽,列数

H为高,行数

 

解题思路:

DFS和BFS的综合题,但是写代码时要注意几方面:

 

1、 左转、右转优先搜索时必须标记当前位置时的方向,我定义的方向是

    


 

最初的方向由起点S确定,而下一步的方向则由前一步的走向决定

 

例如 左边优先搜索:

当前位置的方向面朝1(向左),(这同时说明前一步是在第“3”的位置走过来的)

那么走下一步时,就要根据2103的顺序,先逐格确定当前位置周边的四格是否可行

若第一次确认2(左手边第一方向)可行,就走到2,在位置2时的方向为2(向下)

若2不可行,则再确定1,若1可行,就走到1,在位置1时的方向为1(向左)

若1也不可行,则再确定0,若0可行,就走到0,在位置0时的方向为0(向上)

若0也不可行,说明进入了迷宫的死胡同,要从原路返回,走回3

但走回3时的方向变了,由3到当前位置是方向1,返回时由1到3就变成了方向3,下面就接着这个方向递归的走,看上去是原路返回,实质上可以认为是变换了一个方向继续寻路,只不过返回后的寻路方向变成了0321  !!!

在程序中的表达就是进来时DFS_LF(i,j-1,1); ,返回时就是DFS_LF(i,j+1,3); ,好好理解一下。

 

右边优先搜索也同理。

 

根据我定义的方向,设当前位置为d,那么

左转,用数学式子表达就是  d=(d+1)%4

右转,用数学式子表达就是  d=(d+3)%4

我比较懒,在我的程序中,DFS和BFS都用了多入口的做法,有兴趣的同学可以利用我给出的这两个式子对代码进行优化。

        

这里有一点必须要注意的:

左边、右边优先搜索都不是找最短路,因此走过的路可以再走,无需标记走过的格

 

2、 寻找最短路只能用BFS

因此在做第3问时别傻乎乎的又用DFS,DFS对于样例的输入确实和BFS得到的结果一样的,别以为样例PASS就提交了。。。所以我就说样例没代表性,学会测试数据很重要= =

 

注意有一点:

要求E的最短路,必须把迷宫模拟为树,S为根,找到E所在的层(树深),该层就是S到E的最短路,处理技巧就是在BFS时,令queue[tail]的depth等于对应的queue[head]的depth+1,详细见我的程序。

把循环的次数作为深度就铁定错的。


代码如下

#include<iostream>
using namespace std;

typedef class
{
	public:
		int r,c;
		int depth;
}SE;

SE s,e; //起止点
int Lstep;  //左边优先搜索 时从S到E的总步数
int Rstep;  //右边优先搜索 时从S到E的总步数
int shortstep;  //S到E的最少总步数

bool maze[41][41]; //记录迷宫的“可行域”与“墙”

void DFS_LF(int i,int j,int d)    //左边优先搜索,i,j为当前点坐标,d为当前位置方向
{
	Lstep++;
	if(i==e.r && j==e.c)
		return;

	switch(d)
	{
	    case 0:
			{
				if(maze[i][j-1])
					DFS_LF(i,j-1,1);
				else if(maze[i-1][j])
					DFS_LF(i-1,j,0);
				else if(maze[i][j+1])
					DFS_LF(i,j+1,3);
				else if(maze[i+1][j])
					DFS_LF(i+1,j,2);//相当于原路返回,但是方向由0变成了2
				break;
			}
		case 1:
			{
				if(maze[i+1][j])
					DFS_LF(i+1,j,2);
				else if(maze[i][j-1])
					DFS_LF(i,j-1,1);
				else if(maze[i-1][j])
					DFS_LF(i-1,j,0);
				else if(maze[i][j+1])
					DFS_LF(i,j+1,3);  //相当于原路返回,但是方向由1变成了3
				break;
			}
		case 2:
			{
				if(maze[i][j+1])
					DFS_LF(i,j+1,3);
				else if(maze[i+1][j])
					DFS_LF(i+1,j,2);
				else if(maze[i][j-1])
					DFS_LF(i,j-1,1);
				else if(maze[i-1][j])
					DFS_LF(i-1,j,0);//相当于原路返回,但是方向由2变成了0
				break;
			}
		case 3:
			{
				if(maze[i-1][j])
					DFS_LF(i-1,j,0);
				else if(maze[i][j+1])
					DFS_LF(i,j+1,3);
				else if(maze[i+1][j])
					DFS_LF(i+1,j,2);
				else if(maze[i][j-1])
					DFS_LF(i,j-1,1);//相当于原路返回,但是方向由3变成了1
				break;
			}
	}

//	return;   //不需要return(可AC,原代码中有也可以AC)。
}

void DFS_RF(int i,int j,int d)    //右边优先搜索,i,j为当前点坐标,d为当前位置方向
{
	Rstep++;
	if(i==e.r && j==e.c)
		return;

	switch(d)
	{
	    case 0:
			{
				if(maze[i][j+1])
					DFS_RF(i,j+1,3);
				else if(maze[i-1][j])
					DFS_RF(i-1,j,0);
				else if(maze[i][j-1])
					DFS_RF(i,j-1,1);
				else if(maze[i+1][j])
					DFS_RF(i+1,j,2);
				break;
			}
		case 1:
			{
				if(maze[i-1][j])
					DFS_RF(i-1,j,0);
				else if(maze[i][j-1])
					DFS_RF(i,j-1,1);
				else if(maze[i+1][j])
					DFS_RF(i+1,j,2);
				else if(maze[i][j+1])
					DFS_RF(i,j+1,3);
				break;
			}
		case 2:
			{
				if(maze[i][j-1])
					DFS_RF(i,j-1,1);
				else if(maze[i+1][j])
					DFS_RF(i+1,j,2);
				else if(maze[i][j+1])
					DFS_RF(i,j+1,3);
				else if(maze[i-1][j])
					DFS_RF(i-1,j,0);
				break;
			}
		case 3:
			{
				if(maze[i+1][j])
					DFS_RF(i+1,j,2);
				else if(maze[i][j+1])
					DFS_RF(i,j+1,3);
				else if(maze[i-1][j])
					DFS_RF(i-1,j,0);
				else if(maze[i][j-1])
					DFS_RF(i,j-1,1);
				break;
			}
	}
//	return;//不需要return(可AC,原代码中有也可以AC),因为递归是默认返回的(在这里是 break; 之后)。
}

void BFS_MSS(int i,int j)    //最短路搜索
{
	bool vist[41][41]={false};
	SE queue[1600];
	int head,tail;

	queue[head=0].r=i;
	queue[tail=0].c=j;
	queue[tail++].depth=1;  //当前树深标记,这是寻找最短路的关键点

	vist[i][j]=true;

	while(head<tail)
	{
		SE x=queue[head++];

		if(x.r==e.r && x.c==e.c)
		{
			cout<<x.depth<<endl;
			return;
		}

		if(maze[x.r][x.c-1] && !vist[x.r][x.c-1])
		{
			vist[x.r][x.c-1]=true;
			queue[tail].r=x.r;
			queue[tail].c=x.c-1;
			queue[tail++].depth=x.depth+1;
		}
		if(maze[x.r-1][x.c] && !vist[x.r-1][x.c])
		{
			vist[x.r-1][x.c]=true;
			queue[tail].r=x.r-1;
			queue[tail].c=x.c;
			queue[tail++].depth=x.depth+1;
		}
		if(maze[x.r][x.c+1] && !vist[x.r][x.c+1])
		{
			vist[x.r][x.c+1]=true;
			queue[tail].r=x.r;
			queue[tail].c=x.c+1;
			queue[tail++].depth=x.depth+1;
		}
		if(maze[x.r+1][x.c] && !vist[x.r+1][x.c])
		{
			vist[x.r+1][x.c]=true;
			queue[tail].r=x.r+1;
			queue[tail].c=x.c;
			queue[tail++].depth=x.depth+1;
		}
	}
	return;
}

int main(int i,int j)
{
	int test;
	cin>>test;
	while(test--)
	{
		int direction;  //起点S的初始方向
		int w,h;  //size of maze
		cin>>w>>h;

		/*Initial*/

		Lstep=1;
		Rstep=1;
		memset(maze,false,sizeof(maze));

		/*Structure the Maze*/

		for(i=1;i<=h;i++)
			for(j=1;j<=w;j++)
			{
				char temp;
				cin>>temp;
				if(temp=='.')
					maze[i][j]=true;
				if(temp=='S')
				{
					maze[i][j]=true;
					s.r=i;
					s.c=j;

					if(i==h)
						direction=0;
					else if(j==w)
						direction=1;
					else if(i==1)
						direction=2;
					else if(j==1)
						direction=3;
				}
				if(temp=='E')
				{
					maze[i][j]=true;
					e.r=i;
					e.c=j;
				}
			}

		/*Left First Search*/

		switch(direction)
		{
		    case 0: {DFS_LF(s.r-1,s.c,0); break;}
			case 1: {DFS_LF(s.r,s.c-1,1); break;}
			case 2: {DFS_LF(s.r+1,s.c,2); break;}
			case 3: {DFS_LF(s.r,s.c+1,3); break;}
		}
		cout<<Lstep<<' ';

		/*Right First Search*/

		switch(direction)
		{
		    case 0: {DFS_RF(s.r-1,s.c,0); break;}
			case 1: {DFS_RF(s.r,s.c-1,1); break;}
			case 2: {DFS_RF(s.r+1,s.c,2); break;}
			case 3: {DFS_RF(s.r,s.c+1,3); break;}
		}
		cout<<Rstep<<' ';

		/*Most Short Step Search*/

		BFS_MSS(s.r,s.c);
		
	}
	return 0;
}
转载自 POJ3083

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值