P1519 穿越栅栏 Overfencing

题目描述

描述 农夫John在外面的田野上搭建了一个巨大的用栅栏围成的迷宫。幸运的是,他在迷宫的边界上留出了两段栅栏作为迷宫的出口。更幸运的是,他所建造的迷宫是一个“完美的”迷宫:即你能从迷宫中的任意一点找到一条走出迷宫的路。给定迷宫的宽度W(1<=W<=38)及高度H(1<=H<=100)。 2*H+1行,每行2*W+1的字符以下面给出的格式表示一个迷宫。然后计算从迷宫中最“糟糕”的那一个点走出迷宫所需的步数(就是从最“糟糕”的一点,走出迷宫的最少步数)。(即使从这一点以最优的方式走向最靠近的出口,它仍然需要最多的步数)当然了,牛们只会水平或垂直地在X或Y轴上移动,他们从来不走对角线。每移动到一个新的方格算作一步(包括移出迷宫的那一步)这是一个W=5,H=3的迷宫:

+-+-+-+-+-+

| |

+-+ +-+ + +

| | | |

  • +-+-+ + +

| | |

+-+ +-+-+-+

(请将上图复制到记事本观看更加)

如上图的例子,栅栏的柱子只出现在奇数行或奇数列。每个迷宫只有两个出口。

输入输出格式

输入格式:

第一行: W和H(用空格隔开)

第二行至第2 H + 1行: 每行2 W + 1个字符表示迷宫

输出格式:

输出一个单独的整数,表示能保证牛从迷宫中任意一点走出迷宫的最小步数。

输入输出样例

输入样例#1:
5 3
+-+-+-+-+-+
|         |
+-+ +-+ + +
|     | | |
+ +-+-+ + +
| |     |  
+-+ +-+-+-+
输出样例#1:
9

说明

翻译来自NOCOW

USACO 2.4

此题可以发现出口已被限制为有且仅有两个,因此我们瞬间就可以想到从这两个点开始广搜,更新每个点的最短距离。

但是由于此地图是放大后的,因此每跳过两个格子(字符)才算走了一步

但是:千万注意:格式!若要用gets(),则读完那两个数字后不能用getchar,而要用gets,去掉一个空串,被坑了太久。。。。。。

贴上代码:

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define inf 999999999
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define rep(i,a,b) for(i=(a);i>=(b);--i)
#define mm(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn = 100010;
int vis[1010][1010];
int m,n;
char s[maxn];
int stx1,sty1,stx2,sty2;
int dp[1010][1010];
struct node{
    int x,y,t;
};
int p[1010][1010];
int d[4][2]={{2,0},{-2,0},{0,2},{0,-2}};
int mis[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};//要跨两个则中间那个也不能有障碍
int ansmax;
void solve(int tx,int ty,bool type){
    int i;
    queue<node> q;
    node T;
    T.x = tx,T.y = ty;
    T.t = 0;
    q.push(T);
    p[tx][ty] = 1;
    while(!q.empty()){
        T = q.front();
        q.pop();
        For(i,0,3){
            int u = T.x + d[i][0],v = T.y + d[i][1], u2 = T.x + mis[i][0], v2 = T.y + mis[i][1];
            if(u<1 || v<1 || u>m*2+1 || v>n*2+1 || !vis[u][v] || !vis[u2][v2] || p[u][v])continue;
            p[u][v]=1;
            dp[u][v] = min(dp[u][v],T.t + 1);
            if(type)ansmax = max(dp[u][v] , ansmax);//第二个出口搜的时候再更新
            node h;
            h.x = u,h.y = v;h.t = T.t+1;
            q.push(h);
        }
    }
}
int main(){
    int i,j;
    int cnt = 0;
    int ans = 0;
    scanf("%d%d",&n,&m);
    gets(s);//就是这里
    For(i,1,m*2+1){
        char c;
        ans = 0;
        gets(s);
        For(j,0,n*2){
            if(s[j]==' '){
                if(j==0 || i==1 || i==m*2+1 || j==n*2){
                    ++cnt;
                    if(cnt==1){//这里需要模拟一下
                        if(j==0)stx1 = i,sty1 = j;
                        else if(i==1) stx1 = i-1,sty1 = j+1;
                        else if(i==m*2+1)stx1 = m*2+2,sty1=j+1;
                        else stx1 = i,sty1 = n*2+2;
                    }
                    else{
                        if(j==0)stx2 = i,sty2 = j;
                        else if(i==1) stx2 = i-1,sty2 = j+1;
                        else if(i==m*2+1)stx2 = m*2+2,sty2=j+1;
                        else stx2 = i,sty2 = n*2+2;
                    }
                }
                vis[i][j+1]=1;
            }
            dp[i][j+1] = inf;//初始化
        }
    }
    solve(stx1,sty1,0);
    mm(p,0);
    solve(stx2,sty2,1);
    printf("%d\n",ansmax);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值