POJ-3083 Children of the Candy Corn

8 篇文章 0 订阅
7 篇文章 0 订阅

Children of the Candy Corn
原题链接
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 14564 Accepted: 6283
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
Source

South Central USA 2006

糖果玉米的孩子
[原题链接](http://poj.org/problem?id=3083
时间限制:1000MS内存限制:65536K
总提交内容:14564接受:6283
描述

玉米田迷宫是一种流行的万圣节款待。参观者被显示入口,必须通过的迷宫里面临僵尸徘徊,电锯挥舞着精神病患者,嬉皮士和其他恐怖在追他们直到找到出口。

一种流行的迷宫步行策略保证了游客最终能够找到出口。只需选择右侧或左侧墙壁,然后按照它来走。当然,不能保证哪种策略(左或右)会更好,并且所采用的路径很少是最有效的。 (它也不适用于不在边缘的出口,这种类型的迷宫在这个问题中没有表现出来。)

作为即将变成迷宫的玉米田的主人,你想要有一个计算机程序,可以确定左右两条路径以及最短路径,这样你就可以确定哪个布局具有使访客混淆的最佳机会。
输入

对这个问题的输入将以包含单个整数n的行开始,该整数指示迷宫的数量。每个迷宫将由一条宽度为w,高度为h(3 <= w,h <= 40)的线条组成,后面跟着每行代表迷宫布局的h个字符。墙由哈希标记(’#’)表示,以空格分隔(’。’),以’S’开头并以’E’结尾。

一个’S’和一个’E’将出现在迷宫中,并且它们将始终位于迷宫边缘的一个角落,从不在角落。迷宫将被墙壁(’#’)完全封闭,唯一的开口是’S’和’E’。 ‘S’和’E’也会被至少一个墙(’#’)隔开。

你可以假设迷宫出口总是从起点到达。
输出

对于输入中的每个迷宫,在单行上输出一个人将访问的(不一定是唯一的)正方形的数量(包括’S’和’E’)(左侧,右侧和最短路径) ,每个空格分隔一个空格。只能在水平或垂直方向上从一个方块移动到另一个方块;不允许沿对角线移动。
示例输入

2
8 8
########
#……#
#.####.#
#.####.#
#.####.#
#.####.#
#…#..#
#S#E####
9 5
#########
#.#.#.#.#
S…….E
#.#.#.#.#
#########
示例输出

37 5 5
17 17 9
来源

美国中南部2006年

题解
题目大意是让你输出三种从起点到终点的路径长度,第一种是能往左就往左走,第二种是能往右就往右走,第三种是最短路。
前两种是 DFS 可以实现的,第三种可以用 BFS 来实现。
对于尽量左走的方式,我们每次先看左边能不能走,如果不能,那么我们就看看能否继续前进,再不行就看看右边,最后可以选择回头。也就是左、前、右、后的顺序。(先走右边就按照右、前、左、后的顺序)
不能按照左、前、后、右的顺序,否则会来回打转↓↓

5 4
#####
#. . .#
#. #E#
#s###

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define _x .first
#define _y .second
using namespace std;
const int maxn=45,tt=maxn*maxn,F[4][2]={{0,1},{-1,0},{0,-1},{1,0}};
bool vis;
char mp[maxn][maxn];
int n,m,f[maxn][maxn],sx,sy,tx,ty,INF,hea,til;
pair<int,int>q[tt];
bool pd(int x,int y)
{
    if (x<1||y<1||x>n||y>m||mp[x][y]=='#') return 1;
    return 0;
}
int dfsL(int x,int y,int p)//先往左走
{
    if (pd(x,y)||vis) return INF;//printf("%d %d %d\n",x,y,p);
    if (x==tx&&y==ty) {vis=1;return 1;}
    if (pd(x+F[p+1&3][0],y+F[p+1&3][1]))//按顺序判断4个方向能不能走,先往右的DFS同理
    {
        if (pd(x+F[p][0],y+F[p][1]))
        {
            if (pd(x+F[p+3&3][0],y+F[p+3&3][1])){p=p+2&3;return 1+dfsL(x+F[p][0],y+F[p][1],p);}
            else{p=p+3&3;return 1+dfsL(x+F[p][0],y+F[p][1],p);}
        }
        else{return 1+dfsL(x+F[p][0],y+F[p][1],p);}
    }
    else{p=p+1&3;return 1+dfsL(x+F[p][0],y+F[p][1],p);}
}
int dfsR(int x,int y,int p)//先往右走
{
    if (pd(x,y)||vis) return INF;
    if (x==tx&&y==ty) {vis=1;return 1;}
    if (pd(x+F[p+3&3][0],y+F[p+3&3][1]))
    {
        if (pd(x+F[p][0],y+F[p][1]))
        {
            if (pd(x+F[p+1&3][0],y+F[p+1&3][1])){p=p+2&3;return 1+dfsR(x+F[p][0],y+F[p][1],p);}
            else{p=p+1&3;return 1+dfsR(x+F[p][0],y+F[p][1],p);}
        }
        else{return 1+dfsR(x+F[p][0],y+F[p][1],p);}
    }
    else{p=p+3&3;return 1+dfsR(x+F[p][0],y+F[p][1],p);}
}
void fin(int x,int y,int s)
{
    if (x<1||y<1||x>n||y>m||mp[x][y]=='#'||f[x][y]<=s) return;
    q[(++til)%=tt]=make_pair(x,y);f[x][y]=s;
}
int bfs(int x,int y)
{
    hea=0,til=1;f[x][y]=0;
    q[1]=make_pair(x,y);
    while (hea!=til)
    {
        x=q[(++hea)%=tt]_x;y=q[hea]_y;
        if (x==tx&&y==ty) return f[x][y];
        fin(x+1,y,f[x][y]+1);fin(x-1,y,f[x][y]+1);
        fin(x,y+1,f[x][y]+1);fin(x,y-1,f[x][y]+1);
    }
}
void work()
{
    scanf("%d%d",&m,&n);
    for (int i=1;i<=n;i++)
     for (int j=1;j<=m;j++)
     {
         char ch=getchar();
         while (ch!='.'&&ch!='#'&&ch!='S'&&ch!='E') ch=getchar();
         if (ch=='S') sx=i,sy=j;else
         if (ch=='E') tx=i,ty=j;
         mp[i][j]=ch;
     }
    int k=0;while (pd(sx+F[k][0],sy+F[k][1])) k++;
    memset(f,63,sizeof f);INF=f[0][0];vis=0;
    printf("%d ",dfsL(sx,sy,k));vis=0;
    printf("%d ",dfsR(sx,sy,k));
    printf("%d\n",bfs(sx,sy)+1);
}
int main()
{
    int T;scanf("%d",&T);
    while (T--) work();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值