poj3083Children of the Candy Corn(AC)

来源:互联网 发布:ios11.1 4g网络不好 编辑:程序博客网 时间:2024/05/17 02:57
Children of the Candy Corn
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 11515 Accepted: 4946

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

 

28 8#########......##.####.##.####.##.####.##.####.##...#..##S#E####9 5##########.#.#.#.#S.......E#.#.#.#.##########

Sample Output

37 5 517 17 9

 

 

刚开始题意还是没明白,poj的题目感觉很多题意都很难懂,问的是沿着向左或向右的墙走(Simply choose either the right or left wall, and follow it),而不是一开始理解的只能

向左或向右移动,不是这个意思,还有1个求最小路径,

 

 

题目大意:给一个迷宫,要你分别求出按先考虑左边的方向,和先考虑右边方向走出迷宫所经过的格子,还有走出迷宫经过的最少格子

解题思路:题目不难,比较繁琐,就是深度优先左边遍历和深度优先右边遍历还有就是广度优先遍历迷宫

深度优先遍历和宽度优先遍历时,要区分从上一个格子过来的方向来判断下一个格子的左边右边是哪个格子

http://blog.csdn.net/xiaoxiaoluo/article/details/7548313 这个说明的代码还是有点看不懂

http://www.2cto.com/kf/201208/147488.html

 http://www.2cto.com/kf/201212/172710.html

http://www.cnblogs.com/ZhaoPengkinghold/p/3763530.html


http://www.cnblogs.com/Potato-lover/p/3930138.html

 

小优博客

http://www.cnblogs.com/lyy289065406/archive/2011/07/31/2122369.html


#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#define MAXINT  45char map[MAXINT][MAXINT];  //记住这个,之前误写成int一直输入不对,找了很久int visit[MAXINT][MAXINT];int w = 0; //列int h = 0; //行int leftans = 0;int rightans = 0;int minans = 0;int startx = 0;int starty = 0;int endx = 0;int endy = 0;typedef struct node{int x;int y;int step;}nodes;nodes que[MAXINT*MAXINT];int dir[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };/*左优先  :由S为起点先向左走,不能走的时候需要右旋转,然后再走自己的左方向,这样以至于自己最大程度的沿着图的左方向走,就一直在自己的方向下左旋转沿着自己的左手边走下去,因为题目说明不会死循环,所以一定能出去。(找出规律:每次相对自己的方向遍历左、上、右、下四个方向)右优先:  和左优先刚好相反,由S为起点出发,先向右手边走,没路走时做左旋转,再沿着自己的右手边走,直到找到出口。(找出规律:每次相对自己的方向遍历右、上、左、下四个方向)*///在这道题中因为存在靠左墙和靠右墙的,所以方向数组是不一样的/*这道题有深搜和广搜。深搜还有要求,靠左或靠右。下面以靠左为例,可以把简单分为上北,下南,左西,右东四个方向。向东就是横坐标i不变,纵坐标j加1(i与j其实就是下标)。其他方向也可以这样确定。通过上一步方向可以确定下一步应该从哪个方向开始搜。比如说,是向北走的,就必须先搜西,西不可以走,再搜北,如果北还不可以走,再搜东,最后才是南。其他方向的情况也可以这样推出来。最后走到E点完成了。广搜就是最基础的广搜。*/void GetInput(){int i = 0;int j = 0;for (i = 0; i < h; i++){scanf("%s", &map[i]);}for (i = 0; i < h; i++){for (j = 0; j < w; j++){if ('S' == map[i][j]){startx = i;starty = j;}if ('E' == map[i][j]){endx = i;endy = j;}}}return;}void init(){int i = 0;int j = 0;int tmp = 0;for (i = 0; i < h; i++){for (j = 0; j < w; j++){map[i][j] = '\0';visit[i][j] = 0;que[tmp].x = 0;que[tmp].y = 0;que[tmp++].step = 0;}}leftans = -1;rightans = -1;minans = -1;return;}void GetMinPathBFS(){int front = 0;int back = 0;int i = 0;que[back].x = startx;que[back].y = starty;que[back++].step = 1;int tmpx = 0;int tmpy = 0;int tmpstep = 0;int x1 = 0;int y1 = 0;while (front<back){tmpx = que[front].x;tmpy = que[front].y;tmpstep = que[front].step;for (i = 0; i < 4; i++){x1 = tmpx + dir[i][0];y1 = tmpy + dir[i][1];if (x1 < 0 || x1 >= h || y1 < 0 || y1 >= w) continue;if (visit[x1][y1])continue;if ('#' == map[x1][y1])continue;if ((x1 == endx) && (y1 == endy)){minans = tmpstep + 1;return;}que[back].x = x1;que[back].y = y1;que[back++].step = tmpstep + 1;visit[x1][y1] = 1;}front++;}return;}//深度优先左边搜索/*##########.#.#.#.#S.......E#.#.#.#.##########*/int direction = 0;int leftdr = -1;int up    = 0;int left  = 3;int down  = 2;int right = 1;int dirleft[7][2] = { { 0, -1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 }, { 0, 1 } };  //先左、上、右、下四个方向,后面3个方向是为了补充,因为根据目前的方向那左边的起始点就不一定是从0开始的void GetDirection(){//题目说保证不会在角落里,所以不需要再最后1行然后第1列类似这样的情况//如果在最后一行if (startx == h - 1) //在最后一行则当前方向是向上走,那左边就是西{direction = up; //up-0leftdr = 0;}else if (startx == 0)//在第1行方向就是向下走,那左边就是看东边{direction = down;//down-2leftdr = 2;}else if (starty == w - 1)//在最后一列那就是向左走也就是向西走,左边就是南边{direction = left; //left-3leftdr = 3;}else if (starty == 0)//在第一列那就是向右走也就是向东走,左边就是北边{direction = right;//right-1leftdr = 1;}return;}//这个图画的挺好的http://www.cnblogs.com/tanhehe/archive/2013/06/25/3154483.html//所谓的沿着左墙都是相对于自己现在的位置而言的,相对位置的左边//            北//  |//  |//     西—————|———————————东//      |//  |//  |//            南void GetLeftAnsDFS(int x, int y, int step,int dir,int leftdir){int i = 0;int x1 = 0;int y1 = 0;int leftx = 0;int lefty = 0;int flag = 0;//首先check左边是否是墙,如果不是,就要向上向下找墙if (x < 0 || x >= h || y < 0 || y >= w) return;if ((x == endx) && (y == endy)){leftans = step;//printf("leftsetp = %d\n", step);return;}//leftdir开始找的方向//当沿着最左边缘的墙壁行走的时候,每次搜索的方向都是从当前方向的左边,然后按照顺时针的方向进行搜索的//因为出现当前的不符合条件的话,肯定是因为不是墙,所以就顺时针往下找,因为不是墙前面那个点肯定是可以通过的// { 0, -1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }for (i = leftdir; i < (leftdir + 4); i++){x1 = x + dirleft[i][0];y1 = y + dirleft[i][1];if (x1 < 0 || x1 >= h || y1 < 0 || y1 >= w) continue;//check左边是否是墙if ('#' == map[x1][y1]) continue;flag = 1;  //说明已经这个方向已经访问了,那就不用再访问别的,这边要记录的,然后下面才能break,否则就会一直在里面循环//如果在最后一行if (dirleft[i][0] == -1) //在最后一行则当前方向是向上走,那左边就是西{GetLeftAnsDFS(x1, y1, step + 1, up,0);}else if (dirleft[i][0] == 1)//在第1行方向就是向下走,那左边就是看东边{GetLeftAnsDFS(x1, y1, step + 1, down, 2);}else if (dirleft[i][1] == -1)//在最后一列那就是向左走也就是向西走,左边就是南边{GetLeftAnsDFS(x1, y1, step + 1, left, 3);}else if (dirleft[i][1] == 1)//在第一列那就是向右走也就是向东走,左边就是北边{GetLeftAnsDFS(x1, y1, step + 1, right, 1);}if (1 == flag){break;}}//printf("2:leftsetp = %d\n", step);return;}//深度优先右边搜索 还有这样的说法int dirright[7][2] = { { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } }; //右、上、左、下四个方向void GetRightAnsDFS(int x, int y, int step, int dir, int right){int i = 0;int x1 = 0;int y1 = 0;int flag = 0;//首先check左边是否是墙,如果不是,就要向上向下找墙if (x < 0 || x >= h || y < 0 || y >= w) return;if ((x == endx) && (y == endy)){rightans = step;//printf("leftsetp = %d\n", step);return;}//rightdir开始找的方向//当沿着最左边缘的墙壁行走的时候,每次搜索的方向都是从当前方向的左边,然后按照逆时针的方向进行搜索的//因为出现当前的不符合条件的话,肯定是因为不是墙,所以就逆时针往下找,因为不是墙前面那个点肯定是可以通过的// { 0, -1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }for (i = right; i < (right + 4); i++){x1 = x + dirright[i][0];y1 = y + dirright[i][1];if (x1 < 0 || x1 >= h || y1 < 0 || y1 >= w) continue;//check左边是否是墙if ('#' == map[x1][y1]) continue;flag = 1;  //说明已经这个方向已经访问了,那就不用再访问别的,这边要记录的,然后下面才能break,否则就会一直在里面循环//如果在最后一行if (dirright[i][0] == -1) //这个是决定下一个方向往哪儿,在最后一行则当前方向是向上走,那右就是东{GetRightAnsDFS(x1, y1, step + 1, up, 0);}else if (dirright[i][0] == 1)//在第1行方向就是向下走,那右边就是看西边{GetRightAnsDFS(x1, y1, step + 1, down, 2);}else if (dirright[i][1] == -1)//在最后一列那就是向右走只能向左走也就是向西走,右边就是北边{GetRightAnsDFS(x1, y1, step + 1, left, 1);}else if (dirright[i][1] == 1)//在第一列那就是向右走也就是向东走,右边就是南边{GetRightAnsDFS(x1, y1, step + 1, right, 3);}if (1 == flag){break;}}return;}int main(){int T = 0;int i = 0;freopen("input.txt", "r", stdin);setbuf(stdout, NULL);scanf("%d", &T);for (i = 0; i < T; i++){scanf("%d %d", &w, &h); //w列 h行init();GetInput();GetDirection();//根据开始的位置来判断初始的方向//最初的方向由起点来决定,而下一步的方向由前一步的方向来决定//当沿着最左边缘的墙壁行走的时候,每次搜索的方向都是从当前方向的左边,然后按照逆时针的方向进行搜索的GetLeftAnsDFS(startx, starty, 1, direction, leftdr);GetRightAnsDFS(startx, starty, 1, direction, leftdr);GetMinPathBFS();printf("%d %d %d\n", leftans, rightans, minans);}return 0;}


 

0 0
原创粉丝点击