搜索加标记


Gym - 101755H

题目网址:http://codeforces.com/gym/101755/problem/H

H. Safe Path
time limit per test
2.0 s
memory limit per test
256 MB
input
standard input
output
standard output

You play a new RPG. The world map in it is represented by a grid of n × m cells. Any playing character staying in some cell can move from this cell in four directions — to the cells to the left, right, forward and back, but not leaving the world map.

Monsters live in some cells. If at some moment of time you are in the cell which is reachable by some monster in d steps or less, he immediately runs to you and kills you.

You have to get alive from one cell of game field to another. Determine whether it is possible and if yes, find the minimal number of steps required to do it.

Input

The first line contains three non-negative integers nm and d (2 ≤ n·m ≤ 200000, 0 ≤ d ≤ 200000) — the size of the map and the maximal distance at which monsters are dangerous.

Each of the next n lines contains m characters. These characters can be equal to «.», «M», «S» and «F», which denote empty cell, cell with monster, start cell and finish cell, correspondingly. Start and finish cells are empty and are presented in the input exactly once.

Output

If it is possible to get alive from start cell to finish cell, output minimal number of steps required to do it. Otherwise, output «-1».

Examples
input
Copy
5 7 1
S.M...M
.......
.......
M...M..
......F
output
Copy
12
input
Copy
7 6 2
S.....
...M..
......
.....M
......
M.....
.....F
output
Copy
11
input

Copy
7 6 2
S.....
...M..
......
......
.....M
M.....
.....F
output
Copy
-1
input
Copy
4 4 2
M...
.S..
....
...F
output
Copy
-1
Note

Please note that monsters can run and kill you on start cell and on finish cell as well.


题的大概意思是:给你一个图,然后M点上是怪兽,这个M点的怪兽可以攻击到d距离的人,然后求从S点到F点最短的距离(不能被怪兽攻击到),你和怪兽只能上下左右走,不可以斜着走(大概意思,当时没有读题,看的样例猜的题意)

省赛积分赛做到的题,当时一看,因为看到了n*m的范围,就想到了开一维(因为上次浙大校赛也做过一个,当时也用到了一维)。比赛的时候,写了40.50分钟吧,因为一些小的处理,没有处理好,而且自己心里又着急,就放弃了。

刚刚吃完饭回来,不到20分钟,改了一下就过了,回头想想,当时是真的菜。


大概思路:因为有n*m的范围,直接把数组开成一维,然后字符串和标记数组的下标都从1开始,接着去记录每个出现M的点以及起点和终点的位置。然后我用了一个dd数组来表示M这个怪兽最多可以蔓延到的距离,So,bfs出所有M的点,然后把出现到的范围标记,这儿用了一个处理,就是先把M的位置设为d+1,然后每次蔓延一个距离让它减一,直到0的时候就停止蔓延。

接着在一个bfs去搜起点和终点,然后dis标记距离,最基本的bfs就可以了,只能走dd为0的地方,因为如果大于0,M的怪兽就会攻击你。

代码如下:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int Maxn = 1e6 + 100;
int n,m,t;
int a[Maxn],d;
char str[Maxn];
bool vis[Maxn];
int dis[Maxn];
int dd[Maxn];
int cnt,enx,eny,stx,sty;
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,-1,1};
struct node {
    int x,y;
} g[Maxn];
bool check(int a,int b) {
    if(a >= 1 && b >= 1 && a <= n && b <= m && dd[a * m + b] == 0)
        return true;
    return false;
}
void bfss() {
    queue<node>q;
    for(int i = 0; i < cnt; i++)
        q.push(g[i]);
    while(!q.empty()) {
        node b = q.front();
        q.pop();
        if(dd[b.x * m + b.y] == 0)
            continue;
        for(int i=0; i < 4; i++) {
            int X = b.x + xx[i];
            int Y = b.y + yy[i];
            if(check(X,Y)) {
                node c;
                c.x = X;
                c.y = Y;
                dd[X * m + Y] = dd[b.x * m + b.y] - 1;
                if(dd[X * m + Y] != 0)
                    q.push(c);
            }
        }
    }
    return ;
}

void bfs() {
    queue<node>q;
    node a,b,c;
    a.x = stx;
    a.y = sty;
    vis[stx * m + sty] = 1;
    q.push(a);
    while(!q.empty()) {
        b = q.front();
        q.pop();
        for(int i = 0; i < 4; i++) {
            int X = b.x + xx[i];
            int Y = b.y + yy[i];
            if(check(X,Y) && !vis[X * m + Y]) {
                dis[X * m + Y] = dis[b.x * m + b.y] + 1;
                vis[X * m + Y] = 1;
                c.x = X;
                c.y = Y;
                q.push(c);
            }
        }

    }
}
int main() {
    while(~scanf("%d%d%d",&n,&m,&d)) {
        getchar();
        for(int i = 1; i <= n; i++)
            scanf("%s",&str[i * m + 1]);
        memset(vis,0,sizeof(vis));
        memset(dd,0,sizeof(dd));
        memset(dis,0,sizeof(dis));
        for(int i = 1; i <= n; i++)  {
            for(int j = 1; j <= m; j++) {
                if(str[i * m + j] == 'S')
                    stx = i,sty = j;
                else if(str[i * m + j] == 'F')
                    enx = i,eny = j;
                else if(str[i * m + j] == 'M') {
                    node a;
                    dd[i * m + j] = d + 1;
                    a.x = i;
                    a.y = j;
                    g[cnt++] = a;
                }
            }
        }
        bfss();
        if(dd[stx * m + sty] > 0 || dd[enx * m + eny] > 0) {
            printf("-1\n");
            continue;
        }
        bfs();
        if(dis[enx * m + eny] == 0) {
            printf("-1\n");
        } else printf("%d\n",dis[enx * m + eny]);
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值