poj3083 Children of the Candy Corn【bfs+dfs】【刷题计划】

Children of the Candy Corn
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 14452   Accepted: 6233

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

这道题真考验自己的读题能力,题意是,输出靠左墙走从起点到终点的步数,靠右墙走从起点到终点的步数,从起点到终点的最小步数。

思路:想了很久都不知道怎样实现靠左墙和右墙的判断,后来看了别人的题解才知道,将方向编号,根据上一次的方向,确定下一次搜索方向,因搜索方向的顺序不同而实现靠左墙走和右墙走,比如现在我们是靠左墙走,在此题中,我将上下左右分别编号为0,2,3,1,现在我们所走的方向是0,也就是说,从上一步到现在这一步,我们记录的方向为0,如何判断下一步往哪个方向走才能实现靠左墙走呢,我们就先判断3方向也就是向左的方向是否能够通行,如果不能,再判断0方向也就是向上能否通行,如果不能,再判断1方向,也就是右方向是否能够通行,如果还不行,最后判断2方向,也就是我们只能往回走,综上,搜索顺序就是,3,0,1,2,当然,这只是在我们当前方向为0时且靠左墙走的搜索顺序,其余顺序还要靠自己依次枚举。

总结:睡眠不足真的很影响写题效率,很多小bug就是因为自己疏忽才没有被发现,比如求最小步数时,必须要用数组进行标记,自己连这个都给忽略了,当时还在纠结为什么会重复,现在看来,啊~~~,真是好浪费时间啊,今天晚上没有cf了,早点休息,明天又继续写题,嘻嘻~~~

具体见注释:

#include<stdio.h>
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
#define N 50

char str[N][N];
int n,m,Left,Right,sum,ei,ej;
int k[4][2] = {1,0,-1,0,0,1,0,-1};
int book[N][N];
typedef struct node{
    int x;
    int y;
    int step;
}map;
void Leftdfs(int x,int y,int dire,int step)
{
    if(str[x][y] == 'E')//走到终点时,停止搜索 
    {
        Left = step;
        return;
    }
    switch(dire)
    {
        case 0://如果上一步方向为向上 ,那么我们接下来搜索方向为3,0,1,2 
            {
                if(y-1>=0&&str[x][y-1] != '#')
                    Leftdfs(x,y-1,3,step+1);
                else if(x-1>=0&&str[x-1][y] != '#')
                    Leftdfs(x-1,y,0,step+1);
                else if(y+1<m&&str[x][y+1] != '#')
                    Leftdfs(x,y+1,1,step+1);
                else if(x+1<n&&str[x+1][y] != '#')
                    Leftdfs(x+1,y,2,step+1);
                    break;
            }
        case 1://如果上一步方向为向右,那么我们接下来搜索方向为0,1,2,3 
            {
                if(x-1>=0&&str[x-1][y] != '#')
                    Leftdfs(x-1,y,0,step+1);
                else if(y+1<m&&str[x][y+1] != '#')
                    Leftdfs(x,y+1,1,step+1);
                else if(x+1<n&&str[x+1][y] != '#')
                    Leftdfs(x+1,y,2,step+1);
                else if(y-1>=0&&str[x][y-1] != '#')
                    Leftdfs(x,y-1,3,step+1);
                    break;
            }
        case 2://如果上一步方向为向左,那么我们接下来方向为1,2,3,0 
            {
                if(y+1<m&&str[x][y+1] != '#')
                    Leftdfs(x,y+1,1,step+1);
                else if(x+1<n&&str[x+1][y] != '#')
                    Leftdfs(x+1,y,2,step+1);
                else if(y-1>=0&&str[x][y-1] != '#')
                    Leftdfs(x,y-1,3,step+1);
                else if(x-1>=0&&str[x-1][y] != '#')
                    Leftdfs(x-1,y,0,step+1);
                break;
            }
        case 3://如果上一步方向为向下,那么我们接下来搜索方向为2,3,0,1 
            {
                if(x+1<n&&str[x+1][y] != '#')
                    Leftdfs(x+1,y,2,step+1);
                else if(y-1>=0&&str[x][y-1] != '#')
                    Leftdfs(x,y-1,3,step+1);
                else if(x-1>=0&&str[x-1][y] != '#')
                    Leftdfs(x-1,y,0,step+1);
                else if(y+1<m&&str[x][y+1] != '#')
                    Leftdfs(x,y+1,1,step+1);
                break;
            }
    }
}
void Rightdfs(int x,int y,int dire,int step)//同理亦然 
{
    if(str[x][y] == 'E')
    {
        Right = step;
        return;
    }
    switch(dire)
    {
        case 0:
            {
                if(y+1<m&&str[x][y+1] != '#')
                    Rightdfs(x,y+1,1,step+1);
                else if(x-1>=0&&str[x-1][y] != '#')
                    Rightdfs(x-1,y,0,step+1);
                else if(y-1>=0&&str[x][y-1] != '#')
                    Rightdfs(x,y-1,3,step+1);
                else if(x+1<n&&str[x+1][y] != '#')
                    Rightdfs(x+1,y,2,step+1);
                    break;
            }
        case 1:
            {
                if(x+1<n&&str[x+1][y] != '#')
                    Rightdfs(x+1,y,2,step+1);
                else if(y+1<m&&str[x][y+1] != '#')
                    Rightdfs(x,y+1,1,step+1);
                else if(x-1>=0&&str[x-1][y] != '#')
                    Rightdfs(x-1,y,0,step+1);
                else if(y-1>=0&&str[x][y-1] != '#')
                    Rightdfs(x,y-1,3,step+1);
                    break;
            }
        case 2:
            {
                if(y-1>=0&&str[x][y-1] != '#')
                    Rightdfs(x,y-1,3,step+1);
                else if(x+1<n&&str[x+1][y] != '#')
                    Rightdfs(x+1,y,2,step+1);
                else if(y+1<m&&str[x][y+1] != '#')
                    Rightdfs(x,y+1,1,step+1);
                else if(x-1>=0&&str[x-1][y] != '#')
                    Rightdfs(x-1,y,0,step+1);
                break;
            }
        case 3:
            {
                if(x-1>=0&&str[x-1][y] != '#')
                    Rightdfs(x-1,y,0,step+1);
                else if(y-1>=0&&str[x][y-1]!= '#')
                    Rightdfs(x,y-1,3,step+1);
                else if(x+1<n&&str[x+1][y] != '#')
                    Rightdfs(x+1,y,2,step+1);
                else if(y+1<m&&str[x][y+1] != '#')
                    Rightdfs(x,y+1,1,step+1);
                break;
            }
    }
}
void bfs(int si,int sj,int step)
{
    map s1,s2,s3;
    queue<map>q;
    int i,nx,ny;
    s1.step = step;
    s1.x = si;
    s1.y = sj;
    book[si][sj] = 1;
    q.push(s1);
    while(!q.empty())
    {
        s2 = q.front();
        q.pop();
        if(s2.x == ei&&s2.y == ej)
        {
            sum = s2.step ;
            return;
        }
        for( i = 0; i < 4; i ++)
        {
             nx = s2.x  + k[i][0];
             ny = s2.y  + k[i][1];
            if(nx < 0||ny < 0||nx > n-1||ny > m-1||str[nx][ny] == '#'||book[nx][ny])
                continue;
            if(str[nx][ny] !='#')
            {
                s3.x = nx;
                s3.y = ny;
                s3.step = s2.step +1;
                book[nx][ny] = 1;
                q.push(s3);
            }
        }
    }
    
    return;
}

int main()
{
    int t,si,sj,direction,i,j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&m,&n);
        getchar();
        for( i = 0; i < n; i ++)
        {
            scanf("%s",str[i]);
            for( j = 0; j < m; j ++)
            {
                if(str[i][j] == 'S')//记录起始坐标 
                {
                    si = i;
                    sj = j;
                }
                if(str[i][j] == 'E')//记录终点坐标 
                {
                    ei = i;
                    ej = j;
                }
            }
        }
        if(si  == 0)//判断起始点方向 如果在上边界,那么它只能往下走,起始方向就为2 
            direction = 2;
        else if(si == n-1)//如果在下边界,那么它只能往上走,起始方向为0 
            direction = 0;
        else if(sj == 0)//同理 
            direction = 1;
        else if(sj == m-1)//同理 
            direction = 3;
        Leftdfs(si,sj,direction,1);//靠左墙走 
        Rightdfs(si,sj,direction,1);//靠右墙走 
        memset(book,0,sizeof(book));//由于是求最小步数,因此我们需要数组标记,防止重复行走 
        bfs(si,sj,1);//求最小步数 
        printf("%d %d %d\n",Left,Right,sum);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值