北大acm3083,BFS与DFS的引用

本题需求的基础是广度优先搜索(BFS)以及深度优先搜索(DFS)

题目如下:原题目:
Children of the Candy Corn
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 15543 Accepted: 6688

Description
The cornfield maze is a popular Halloween treat. Visitors are shown the entrance and must wander through the maze facing zombies, chainsaw-wielding psychopaths, hippies, and other terrors on their quest to find the exit.

One popular maze-walking strategy guarantees that the visitor will eventually find the exit. Simply choose either the right or left wall, and follow it. Of course, there’s no guarantee which strategy (left or right) will be better, and the path taken is seldom the most efficient. (It also doesn’t work on mazes with exits that are not on the edge; those types of mazes are not represented in this problem.)

As the proprieter of a cornfield that is about to be converted into a maze, you’d like to have a computer program that can determine the left and right-hand paths along with the shortest path so that you can figure out which layout has the best chance of confounding visitors.

Input
Input to this problem will begin with a line containing a single integer n indicating the number of mazes. Each maze will consist of one line with a width, w, and height, h (3 <= w, h <= 40), followed by h lines of w characters each that represent the maze layout. Walls are represented by hash marks (’#’), empty space by periods (’.’), the start by an ‘S’ and the exit by an ‘E’.

Exactly one ‘S’ and one ‘E’ will be present in the maze, and they will always be located along one of the maze edges and never in a corner. The maze will be fully enclosed by walls (’#’), with the only openings being the ‘S’ and ‘E’. The ‘S’ and ‘E’ will also be separated by at least one wall (’#’).

You may assume that the maze exit is always reachable from the start point.

Output
For each maze in the input, output on a single line the number of (not necessarily unique) squares that a person would visit (including the ‘S’ and ‘E’) for (in order) the left, right, and shortest paths, separated by a single space each. Movement from one square to another is only allowed in the horizontal or vertical direction; movement along the diagonals is not allowed.

Sample Input
2
8 8
########
#…#
#.####.#
#.####.#
#.####.#
#.####.#
#…#…#
#S#E####
9 5
#########
#.#.#.#.#
S…E
#.#.#.#.#
#########

Sample Output
37 5 5
17 17 9

题目大意: 本题要求的是给定一共迷宫要求按照左手走和右手走的方式输出步数,以及最少步数是多少,左手走的意思是优先考虑左手,右手走的意思是优先考虑右手,具体请看解题思路。
解题思路: 首先建立迷宫时我们要确认起点的朝向,例如:起点朝向为 ,那么左手检索的顺序为:←↑→↓;右手检索的顺序为:→↑←↓;本题需要规定好每个方向的编号0123,然后再代码中设立起点就确认朝向,运用DFS算法来检索步数,求最少步数时运用的是BFS 用DFS数据大的话会炸码…
源码如下:

//本题定义的方向(0123)分别为:西(左),北(上),东(右),南(下)
#include<iostream>
#include<queue>
using namespace std;

typedef struct
{
	int x,y;//横,纵坐标
	int min;
}SE;

SE s,e,min1,min2;//起点和终点的结构体,最小步数的结构体
int Lstep;
int Rstep;//定义全局变量分别为左转的步数和右转的步数
int MinStep;//最少步数
int wide,high;//定义迷宫的长与高
bool build[255][255];//定义了可行域和墙所形成的结构体

void DFS_Left(int i,int j,int face)//i,j分别为所在位置的横纵坐标,face是所面向的左转的位置,用来确认自身的位置
{
	Lstep++;
	if(e.x==i && e.y==j)//若走到终点直接停止
		return;

	switch(face)
	{
	case 0://面向:←  检索顺序:↓3012
		{
			if(build[i][j-1])
				DFS_Left(i,j-1,3);

			else if(build[i-1][j])
				DFS_Left(i-1,j,0);

			else if(build[i][j+1])
				DFS_Left(i,j+1,1);

			else if(build[i+1][j])
				DFS_Left(i+1,j,2);
			break;
		}
	case 1://面向:↑  检索顺序:←0123
		{
			if(build[i-1][j])
				DFS_Left(i-1,j,0);

			else if(build[i][j+1])
				DFS_Left(i,j+1,1);

			else if(build[i+1][j])
				DFS_Left(i+1,j,2);

			else if(build[i][j-1])
				DFS_Left(i,j-1,3);
			break;
		}
	case 2://面向:→  检索顺序:↑1230
		{
			if(build[i][j+1])
				DFS_Left(i,j+1,1);

			else if(build[i+1][j])
				DFS_Left(i+1,j,2);

			else if(build[i][j-1])
				DFS_Left(i,j-1,3);

			else if(build[i-1][j])
				DFS_Left(i-1,j,0);
			break;
		}
	case 3://面向:↓  检索顺序:→2301
		{
			if(build[i+1][j])
				DFS_Left(i+1,j,2);

			else if(build[i][j-1])
				DFS_Left(i,j-1,3);

			else if(build[i-1][j])
				DFS_Left(i-1,j,0);

			else if(build[i][j+1])
				DFS_Left(i,j+1,1);
			break;
		}
	}
	return;//void没有返回值 但是要结束可以使用不存在返回值的return
}

void DFS_Right(int i,int j,int face)//i,j分别为所在位置的横纵坐标,face是所面向的右转的位置,用来确认自身的位置
{
	Rstep++;
	if(e.x==i && e.y==j)//若走到终点直接停止
		return;

	switch(face)
	{
	case 0://面向←0  检索顺序:↑1032
		{
			if(build[i][j+1])
				DFS_Right(i,j+1,1);

			else if(build[i-1][j])
				DFS_Right(i-1,j,0);

			else if(build[i][j-1])
				DFS_Right(i,j-1,3);

			else if(build[i+1][j])
				DFS_Right(i+1,j,2);
			break;
		}
	case 1://面向↑1  检索顺序:→2103 
		{
			if(build[i+1][j])
				DFS_Right(i+1,j,2);

			else if(build[i][j+1])
				DFS_Right(i,j+1,1);

			else if(build[i-1][j])
				DFS_Right(i-1,j,0);

			else if(build[i][j-1])
				DFS_Right(i,j-1,3);
			break;
		}
	case 2://面向→2  检索顺序:↓3210 
		{
			if(build[i][j-1])
				DFS_Right(i,j-1,3);

			else if(build[i+1][j])
				DFS_Right(i+1,j,2);

			else if(build[i][j+1])
				DFS_Right(i,j+1,1);

			else if(build[i-1][j])
				DFS_Right(i-1,j,0);
			break;
		}
	case 3://面向↓3  检索顺序:←0321
		{
			if(build[i-1][j])
				DFS_Right(i-1,j,0);

			else if(build[i][j-1])
				DFS_Right(i,j-1,3);

			else if(build[i+1][j])
				DFS_Right(i+1,j,2);

			else if(build[i][j+1])
				DFS_Right(i,j+1,1);
			break;
		}
	}
	return;//void没有返回值 但是要结束可以使用不存在返回值的return
}

void BFS_Min(int i,int j)
{
	bool visited[255][255];//标记已经走过的路程
	memset(visited,false,sizeof(visited));//初始化所有元素
	queue<SE>q;//定义一个队列
	min1.x=i;
	min1.y=j;//定义起点
	visited[min1.x][min1.y]=true;//设计成已经访问过
	min1.min=1;//初始化步数
	q.push(min1);
	int flag=0;
	while(!q.empty())
	{
		if(flag)
			break;
		min1=q.front();
		q.pop();
		for(int i=0;i<4;i++)//一共只可以尝试四个点
		{
			if(i == 0)
			{
				min2.x=min1.x-1;
				min2.y=min1.y;
			}
			else if(i == 1)
			{
				min2.x=min1.x+1;
				min2.y=min1.y;
			}
			else if(i == 2)
			{
				min2.x=min1.x;
				min2.y=min1.y-1;
			}
			else if(i == 3)
			{
				min2.x=min1.x;
				min2.y=min1.y+1;
			}//分别探索四个点,顺序没有要求 探索到四个点就行
			if(min2.x>=1 && min2.x<=high && min2.y>=1 && min2.y<=wide && !visited[min2.x][min2.y] && build[min2.x][min2.y])
			{//要确保没被访问过 并且可走
				min2.min=min1.min+1;
				visited[min2.x][min2.y]=true;
				if(min2.x==e.x && min2.y==e.y)
				{
					flag=1;
					MinStep=min2.min;					
					break;
				}
				q.push(min2);
			}
		}
	}
}

int main()
{
	int sum;//定义一共有多少个迷宫
	cin>>sum;

	while(sum--)//此类的循环可以常用
	{
		int face;//定义起点的朝向,也就是初始位置的朝向
		cin>>wide>>high;//注意high是横 wide是纵
		Lstep=0;
		Rstep=0;//初始化两个步数
		MinStep=0;
		memset(build,false,sizeof(build));//初始化所有的迷宫原数均为false
		for(int i=1;i<=high;i++)//从1开始循环更加容易懂
		{
			for(int j=1;j<=wide;j++)
			{
				char ch;
				cin>>ch;
				if(ch == '.')
					build[i][j]=true;
				if(ch == 'S')
				{
					s.x=i;
					s.y=j;
					build[i][j]=true;

					if(i == high)
						face=0;//初始方向面向0←
					else if(j == wide)
						face=1;//初始方向面向1↑
					else if(i == 1)
						face=2;//初始方向面向2→
					else if(j == 1)
						face=3;//初始方向面向3↓
				}
				if(ch == 'E')
				{
					e.x=i;
					e.y=j;
					build[i][j]=true;
				}
			}
		}
		DFS_Left(s.x,s.y,face);
		cout<<Lstep<<" ";
		DFS_Right(s.x,s.y,face);
		cout<<Rstep<<" ";
		BFS_Min(s.x,s.y);
		cout<<MinStep<<endl;
	}
	return 1;
}

再提供一些测试数据(感谢这位朋友发的数据): 添加链接描述

猜你喜欢

转载自blog.csdn.net/weixin_43626529/article/details/87535834