POJ-3083-Children of the Candy Corn

N - Children of the Candy Corn
Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u
Submit

Status

Practice

POJ 3083
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

三道简单题摞一块的难题。
题意:给出地图,分别输出三种走法所需的步数。
第一种:左转优先,只要左手边有路,就一直左转,左手边没路就看看身后,身后没路就看看右手边,这样七拐八拐后总会到达终点。
第二种:右转优先,同左手优先
第三种:最短步数

基本思路:左转优先和右手优先用深度递归搜索,最短步数用广度优先搜索。
明确思路后,先来看看如何处理前两种情况。
以第一种左转优先为例。
声明左转指向的数组

dir_left[4][2]= {{0,1},{1,0},{0,-1},{-1,0}}; //左转优先搜索方向

声明代表方向的变量point,point=3时,dir_left[point][0]就能代表往左搜索,point=0时往上搜索,point=1时,往右搜索,point=2时,往下搜索。
这样利用point数值的改变,配合搜索方向数组,就能实现左转优先搜索。
右转优先搜索也一样,只不过要改变搜索方向数组中坐标的排序

dir_right[4][2]= {{0,-1},{1,0},{0,1},{-1,0}}; //右转优先搜索方向

第三种最短路广度优先搜索,任意选用上面一个搜索方向数组就可以了。
优先队列http://blog.csdn.net/qq_32680617/article/details/50850309

代码

#include<stdio.h>
#include<string.h>
#include<string>
#include<stack>
#include<queue>
#include<math.h>
#include<limits.h>
#include<iostream>
#include<algorithm>
#define SIZE 100001
using namespace std;
//左转优先,右转优先,最短路
//模拟 模拟 广度优先搜索
char map[44][44];//地图数据
int visited[44][44];//已访问的坐标标记为1,未访问的初始化为0
int dir[4][2]= {{0,1},{1,0},{0,-1},{-1,0}};//最短路搜索方向
int dir_left[4][2]= {{0,1},{1,0},{0,-1},{-1,0}}; //左转优先搜索方向
int dir_right[4][2]= {{0,-1},{1,0},{0,1},{-1,0}}; //右转优先搜索方向
int star_x,star_y;//起始点坐标
int size_x,size_y;//地图尺寸
int point;//记录指向
struct node
{
    int x;
    int y;
    int time;
    friend bool operator<(node test_1,node test_2)
    {
        return test_1.time>test_2.time;//广搜用时少的先出队
    }
};
int judge(int x,int y)//判断坐标是否合法
{
    if(x>=0&&x<size_x&&y>=0&&y<size_y&&map[x][y]!='#'&&visited[x][y]==0)
        return 1;//坐标合法且未被访问返回1
    return 0;
}
int left_DFS(int x,int y,int step)//左转优先,传入当前点坐标及已用步数
{
    if(map[x][y]=='E')//递归终止条件,到终点返回
        return step+1;
    if(judge(x,y)==0)//当前坐标不可通行
        return 0;
    point=(point+3)%4;//代表当前方向的指向
    int flag=0;//暂时记录步数
    while(1)
    {
        flag=left_DFS(x+dir_left[point][0],y+dir_left[point][1],step+1);
        if(flag>0)
            break;
        point=(point+1)%4;
    }
    return flag;
}
int right_DFS(int x,int y,int step)//右转优先,传入当前点坐标及已用步数
{
    if(map[x][y]=='E')
        return step+1;
    if(judge(x,y)==0)
        return 0;
    point=(point+3)%4;
    int flag=0;
    while(1)
    {
        flag=right_DFS(x+dir_right[point][0],y+dir_right[point][1],step+1);
        if(flag>0)
            break;
        point=(point+1)%4;
    }
    return flag;
}
void BFS()//广搜最短路
{
    priority_queue<node>q;
    node star,end;
    star.x=star_x;
    star.y=star_y;
    star.time=1;//此处可能出错
    memset(visited,0,sizeof(visited));
    visited[star.x][star.y]=1;//标记起点已访问
    q.push(star);
    while(!q.empty())
    {
        star=q.top();
        q.pop();
        if(map[star.x][star.y]=='E')
        {
            printf("%d\n",star.time);
            return;
        }
        for(int i=0; i<4; i++)
        {
            end.x=star.x+dir[i][0];
            end.y=star.y+dir[i][1];
            if(judge(end.x,end.y))
            {
                end.time=star.time+1;
                visited[end.x][end.y]=1;
                q.push(end);
            }
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&size_y,&size_x);//注意输入地图尺寸时,x,y反过来了
        for(int i=0; i<size_x; i++)
        {
            for(int j=0; j<size_y; j++)
            {
                cin>>map[i][j];
                if(map[i][j]=='S')
                {
                    star_x=i;
                    star_y=j;
                }
            }
        }
        memset(visited,0,sizeof(visited));//初始化标记
        point=0;//指向归零
        printf("%d ",left_DFS(star_x,star_y,0));
        point=0;//指向归零
        printf("%d ",right_DFS(star_x,star_y,0));
        BFS();
    }
    return 0;
}

挺水的一道题,洋洋洒洒写了一百多行,如果变量命名不规范,写下来能累死人。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值