【gfoj】Problem#787: 密室逃脱

2 篇文章 0 订阅

Problem 787: 密室逃脱
Time Limit: 2000 ms Memory Limit: 524288 KB

Problem Description
小J被关在密室里!

密室的构造是一个H×W的棋盘,即有H行W列,第i行第j列的房间用Ai,j 表示。

若Ai,j =’#’,则该房间的门是锁上的;

若Ai,j =’.’,则该房间是可以自由进出的;

小J被困在Ai,j =’S’的地方,该房间是可以自由进出的。

房间是四相邻的,即(i,j)可以移动到(i+1,j),(i-1,j),(i,j-1),(i,j+1)

小J将通过如下方式逃脱密室,每一回合,她会按顺序执行如下操作:

移动至多K 次,可以不移动,此时被锁着的房间是不能够进入的
选择至多K个锁着的房间打开,可以不选择任何房间,从此那些房间将一直可以自由进出。
出口在密室的四周,即第1行,第1列,第H行,第W列的所有房间,出口一开始可能是被锁住的。

你需要用最少的回合移动到出口,输出这个回合数。

数据范围和子任务:

3≦H≦800

3≦W≦800

1≦K≦H×W

Ai,j 是 ‘#’ ‘.’ ‘S’ 中的一种,有且仅有一个Ai,j 为S

Subtask1(30分):H≦4,W≦4;

Subtask2(10分):不存在Ai,j =#

Subtask3(10分):不存在Ai,j =.

Subtask4(50分):无特殊限制

Input
第一行读入三个整数H,W,K

接下来H行,每行W个字符,表示Ai,j。

Output
输出一行一个数,表示小J最少要用多少回合逃出密室。

Sample Input
【样例输入1】

3 3 3

#.#

#S.

###

【样例输入2】

3 3 3

###

#S#

###

【样例输入3】

7 7 2

#######

#######

##...##

###S###

##.#.##

###.###

#######

Sample Output
【样例输出1】

1

【样例输出2】

2

【样例输出3】

2

【样例解释】

对于样例1:

小J可以在一个回合内移动到(1,2)

对于样例2:

小J第一个回合不能移动,但她解锁了房间(1,2),然后她在第二个回合移动到(1,2)逃离密室。

Problem Source
dhr

题解

一开始理解错题意
题意:

小J将通过如下方式逃脱密室,每一回合,她会按顺序执行如下操作:

移动至多K 次,可以不移动,此时被锁着的房间是不能够进入的
选择至多K个锁着的房间打开,可以不选择任何房间,从此那些房间将一直可以自由进出。

说明一个回合中可以有两种操作
一个回合走的k次可以由前一回合解锁
所以路径对答案没有影响
所以走直线到边界最优

我们先走k次(一回合)
用这一回合走的点更新答案
可以用bfs实现
时间O(n*m)

比赛时看出是搜索题
以为要走奇奇怪怪的路线
找不到结论就做其他题去了
没能签到
有点亏啊

参考文献

[1]AtCoder Grand Contest 014做题记录
[2]cs的比赛总结

ac代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#define N 810
#define INF 2147483647
using namespace std;
int dx[4]={0,-1,0,1},dy[4]={1,0,-1,0},n,m,k,ans,sx,sy,num,u,v;
bool a[N][N],b[N][N];
char ch;
struct Node{
    int x,y,dep;
};
queue<Node>Q;
void Bfs(){
    int x,y,dep;
    while(!Q.empty()){
        x=Q.front().x; y=Q.front().y; dep=Q.front().dep; Q.pop();
        if(x==1||x==n||y==1||y==m){
            ans=0;
            return;
        }
        num=min(min(n-x,m-y),min(x-1,y-1));
        num=(num-1)/k+1;
        ans=min(ans,num);
        for(int i=0;i<4;i++){
            u=x+dx[i]; v=y+dy[i];
            if(!b[u][v]&&a[u][v]&&dep<k&&u>=1&&u<=n&&v>=1&&v<=m){
                b[x][y]=1;
                Q.push((Node){u,v,dep+1});
            }
        }
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            while((ch=getchar())!='#'&&ch!='.'&&ch!='S');
            if(ch=='.')a[i][j]=1;
            else if(ch=='S'){
                a[i][j]=1;
                sx=i; sy=j;
            }
        }
    }
    if(sx==1||sx==n||sy==1||sy==m){
        printf("0\n");
        return 0;
    }
    ans=INF;
    Q.push((Node){sx,sy,0});
    Bfs();
    printf("%d\n",ans+1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值