POJ 3083 Children of the Candy Corn BFS

/*
Children of the Candy Corn
Time Limit: 1000MS  Memory Limit: 65536K 
Total Submissions: 5995  Accepted: 2622
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

  思路:
	题意就是给你一个迷宫,S为起点,E为终点
	找出向左走到终点的解,向右走到终点的解,和最优走到终点的解
    如果没错大概就是左右的按序DFS,最优BFS 注意一开始用DFS处理最优解结果超时,一定要用队列模拟BFS 
	为了思路清晰,我还是写了3个函数,虽然左右的方法基本一致,代码也大部分重复
*/
#include<stdio.h>
#include<string.h>
int visit[200][200];
int stepx[4]={0,1,0,-1};           
//按上右下左的排序处理走的路径 分别为0,1,2,3  
int stepy[4]={-1,0,1,0};             												   
char map[200][200];			       
//记录迷宫                                         
int x,y;                           
//x,y边界
int startx,starty,endx,endy;       
//起始点x,y坐标和终止点x,y坐标
int getway(int gx,int gy){         
	//用于第一步寻找方向 是否要考虑SE靠在一起?
	int way;
	if((map[gy][gx+1] == '#' || map[gy][gx+1] == 'E') && (map[gy][gx-1] == '#' || map[gy][gx-1] == 'E') && gy+1==y ) way = 0;    
	//上
	if((map[gy+1][gx] == '#' || map[gy+1][gx] == 'E') && (map[gy-1][gx] == '#' || map[gy-1][gx] == 'E') && gx-1<0 ) way = 1;	 
	//右
	if((map[gy][gx+1] == '#' || map[gy][gx+1] == 'E') && (map[gy][gx-1] == '#' || map[gy][gx-1] == 'E') && gy-1<0 ) way = 2;     
	//下
	if((map[gy+1][gx] == '#' || map[gy+1][gx] == 'E') && (map[gy-1][gx] == '#' || map[gy-1][gx] == 'E') && gx+1==x ) way = 3;    
	//左
	return way;
}
void lbfs(int lx,int ly,int way,int length){                  
	//左优先
	if(length == 1){                                           
		//伟大的第一步,判断第一步方向
		if(way == 0){ly--;}
		if(way == 1){lx++;}
		if(way == 2){ly++;}
		if(way == 3){lx--;}
		lbfs(lx,ly,way,++length);
	}else if(lx == endx && ly == endy) {printf("%d ",length);}           
	//递归结束
	else{
		for(int j = 0 ; j < 4 ; j++){
			int lway= (way + 3 + j)%4;                                   
			//这句是精华,简单来说就是先左走,走不通就上走,再不通就右走,再不通就回头
			//一定要定义lway暂时储存方向,因为way可能会被下次循环使用
			if(map[ly+stepy[lway]][lx+stepx[lway]] != '#' && 
				lx+stepx[lway] >= 0 && lx+stepx[lway] < x && 
				ly+stepy[lway] >= 0 && ly+stepy[lway] < y) 
			{												             
				lbfs(lx+stepx[lway],ly+stepy[lway],lway,++length);       
				//递归
				return;
			}
		}
	}
}
void rbfs(int rx,int ry,int way,int length){                             
	//右优先 ,和左优先思路一样
	if(length == 1){
		if(way == 0){ry--;}
		if(way == 1){rx++;}
		if(way == 2){ry++;}
		if(way == 3){rx--;}
		rbfs(rx,ry,way,++length);
	}else if(rx == endx && ry == endy) {printf("%d ",length);}
	else{
		for(int j = 0 ; j < 4 ; j++){
			int rway = (way + 5 - j) % 4;
			if(map[ry+stepy[rway]][rx+stepx[rway]] != '#' && rx+stepx[rway] >= 0 && rx+stepx[rway] < x && 
				ry+stepy[rway] >= 0 && ry+stepy[rway] < y){
				rbfs(rx+stepx[rway],ry+stepy[rway],rway,++length);
				return;
			}
		}
	}
}
int fbfs(int fx,int fy,int way,int length){                   
	//最短路径
	if(length == 1){
		memset(visit,0,sizeof(visit));
		visit[fy][fx] = 1;
		if(way == 0){fy--;}
		if(way == 1){fx++;}
		if(way == 2){fy++;}
		if(way == 3){fx--;}
		fbfs(fx,fy,way,++length);
	}else{
		int queue[2000][3],head=0,tail=1,i;      
		//定义队列
		memset(queue,0,sizeof(queue));
		queue[0][0] = fx;                        
		//第一步入队
		queue[0][1] = fy;
		queue[0][2] = way;
		visit[fy][fx] = 1;
		while(1){                                
			//无限循环 return 跳出循环
			int p = tail;
			while(head < p){                     
				// p记录队尾
				for(i = 0 ; i < 3 ; i++)
				{
					int fway = (queue[head][2] + 3 + i) % 4;
					if( (map[queue[head][1] + stepy[fway]][queue[head][0]+ stepx[fway]] == '.'    
						|| map[queue[head][1] + stepy[fway]][queue[head][0]+ stepx[fway]] == 'E')
						&& visit[queue[head][1] + stepy[fway]][queue[head][0]+ stepx[fway]] == 0 )
						//如果周围无墙或是结束就入队
					{

						queue[tail][0] = queue[head][0] + stepx[fway];
						queue[tail][1] = queue[head][1] + stepy[fway];
						queue[tail][2] = fway;
						visit[queue[tail][1]][queue[tail][0]] = 1;
						if(queue[tail][0] == endx && queue[tail][1] == endy)
						{
							return ++length;
						}
						++tail;
					}
				}
				++head;
			}
			length++;
		}
	}
}   
int main(){
//	freopen("in.txt","r",stdin);
	int n;
	scanf("%d",&n);
	while(n--){
		scanf("%d%d",&x,&y);
		int i,j;
		for(i = 0 ; i < y ; i++)
		{
			getchar(); 
			for(j = 0 ; j < x ; j++)
			{
				scanf("%c",&map[i][j]);
				if(map[i][j] == 'S'){startx = j;starty = i;}    
				//确定始末坐标
				else if(map[i][j] == 'E'){endx = j;endy = i;}
			}
		}	
		lbfs(startx,starty,getway(startx,starty),1);
		rbfs(startx,starty,getway(startx,starty),1);
		printf("%d\n",fbfs(startx,starty,getway(startx,starty),1));
	}
	return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值