死亡洞穴

Problem 117: 死亡洞穴


Time Limit:1 Ms| Memory Limit:64 MB
Difficulty:3


Description
在 caima 的 RPG 游戏中,控制着两个人 VV 和 JJ。
这次 VV 和 JJ 掉入了一个死亡洞穴,洞穴是一个 N*M 的矩阵。之所以称之
为死亡洞穴,是因为在这个矩阵中有一些死亡十字。(如下图中的+)
.....
.+++.
.+.+.
V+.J+
由于 VV 和 JJ 被分撒在了两地,而 JJ 还受了重伤,你需要让 VV 赶到 JJ 所
在的地方。为了尽量少的受死亡十字的影响,VV 要尽量远离这些死亡十字。
我们定义洞穴中两个格子(x,y)和(x’,y’)之间的距离为:|x-x'| + |y-y'|
也就是说,我们要使得 VV 再去找 JJ 的路上,离任意死亡十字的距离都尽
可能的远。VV 每次可以往一个格子的上下左右四个方向走一格。
现在你需要写个程序,来计算最好情况下离死亡十字最近的距离。
Input
第一行两个整数 N 和 M,表示矩阵规模。
接下来 N 行 M 列,描述这个洞穴的情况。其中
V 表示 VV 所在的位置;
J 表示 JJ 所在的位置;
. 表示空地;
+ 表示死亡十字。
Output
一行一个数字,表示 VV 在去找 JJ 的路上,最好情况下离死亡十字最近的距离。


Sample Input
4 4
+...
....
....
V..J


Sample Output
3
Hint
数据规模
对于 30% 的数据 N,M<=50。
对于 100% 的数据 N,M<=500。


Source
软件大赛


思路:首先要预处理,初始化每个点到十字的最短距离,用作map,方法是广搜,遍历一下输入的整张图,遇到十字就进队列,然后作为开始广搜,搜到队列为空时,就实现了所有十字同步向外扩散,遍历一遍数组即全都初始化为距离十字的最小值。然后思路是从距离的大到小枚举,遇到最大的可以连通的就是答案,每次枚举一个距离,走大于等于这个距离的点。但是为了减少搜索次数,用二分的思想。深搜广搜都可以。另外,距离最大不会超过起点到十字的距离,因为若大于,起点都不能走。故二分的左边界是0,右边界是起点到十字的距离。


二分穷举距离时深搜:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
 
using namespace std;
 
typedef struct{
    int r, c;
    int step;
}node;
 
int ans, flag, mid, s_x, s_y, e_x, e_y;
int n, m, map[505][505], vis[505][505];
int dir[4][4] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
char temp[505][505];
 
void init();
void init_bfs(int i, int j);
void dfs(int r, int c);
int main(){
    int i, j, r, l;
    int Max, Min;
     
    scanf("%d %d", &n, &m);
     
    for(i = 0; i < n; i++)
        scanf("%s", temp[i]);
     
    init();
     
    ans = 0;
    l = 0;
    r = map[s_x][s_y];
     
    while(l <= r){
        mid = (l + r) / 2;
         
        memset(vis, 0, sizeof(vis));
        flag = 0;
        dfs(s_x, s_y);
        if(flag){
            if(ans < mid)
                ans = mid;
            l = mid + 1;
        }
        else
            r = mid - 1;
    }
     
    printf("%d\n", ans);
    return 0;
}
 
void dfs(int r, int c){
     
    if(r < 0 || r >= n || c < 0 || c >= m || vis[r][c] || map[r][c] < mid)
        return ;
         
    if(r == e_x && c == e_y){
        flag = 1;
        return ;
    }
     
    vis[r][c] = 1;
    dfs(r - 1, c);
    dfs(r + 1, c);
    dfs(r, c - 1);
    dfs(r, c + 1);
}
void init(){
    int i, j, k, row, col;
    node p, q;
    queue <node> Q;
     
    memset(vis, 0, sizeof(vis));
    for(i = 0; i < n; i++){
        for(j = 0; j < m; j++){
            if(temp[i][j] == '+'){
                map[i][j] = 0;
                p.r = i;
                p.c = j;
                p.step = 0;
                vis[i][j] = 1;
                Q.push(p);
            }
            if(temp[i][j] == 'V'){
                s_x = i;
                s_y = j;
            }
            if(temp[i][j] == 'J'){
                e_x = i;
                e_y = j;
            }
        }
    }
     
    while(!Q.empty()){
        q = Q.front();
        Q.pop();
         
        for(k = 0; k < 4; k++){
            row = q.r + dir[k][0];
            col = q.c + dir[k][1];
             
            if(row >= 0 && row < n && col >= 0 && col < m && !vis[row][col]){
                vis[row][col] = 1;
                p.r = row;
                p.c = col;
                p.step = q.step + 1;
                map[row][col] = p.step;
                Q.push(p);
            }
        }
    }
}

二分穷举距离时广搜:


#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
 
using namespace std;
 
typedef struct{
    int r, c;
    int step;
}node;
 
int ans, flag, s_x, s_y, e_x, e_y;
int n, m, map[505][505], vis[505][505];
int dir[4][4] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
char temp[505][505];
 
void init();
void init_bfs(int i, int j);
void bfs(int mid);
int main(){
    int i, j, r, l, mid;
    int Max, Min;
     
    scanf("%d %d", &n, &m);
     
    for(i = 0; i < n; i++)
        scanf("%s", temp[i]);
     
    for(i = 0; i < n; i++){
        for(j = 0; j < m; j++){
            map[i][j] = 65535;
        }
    }
     
    init();
     
    ans = 0;
    l = 0;
    r = map[s_x][s_y];
     
    while(l <= r){
        mid = (l + r) / 2;
         
        memset(vis, 0, sizeof(vis));
        flag = 0;
        bfs(mid);
        if(flag){
            if(ans < mid)
                ans = mid;
            l = mid + 1;
        }
        else
            r = mid - 1;
    }
     
    printf("%d\n", ans);
    return 0;
}
 
void bfs(int mid){
    int i, row, col;
    node p, q;
    queue <node> Q;
     
    p.r = s_x;
    p.c = s_y;
    vis[p.r][p.c] = 1;
    Q.push(p);
     
    while(!Q.empty()){
        q = Q.front();
        Q.pop();
        if(q.r == e_x && q.c == e_y){
            flag = 1;
            return ;
        }
         
        for(i = 0; i < 4; i++){
            row = q.r + dir[i][0];
            col = q.c + dir[i][1];
             
            if(row >= 0 && row < n && col >= 0 && col < m && !vis[row][col] && map[row][col] >= mid){
                vis[row][col] = 1;
                p.r = row;
                p.c = col;
                Q.push(p);
            }
        }
    }
}
 
void init(){
    int i, j, k, row, col;
    node p, q;
    queue <node> Q;
     
    memset(vis, 0, sizeof(vis));
    for(i = 0; i < n; i++){
        for(j = 0; j < m; j++){
            if(temp[i][j] == '+'){
                map[i][j] = 0;
                p.r = i;
                p.c = j;
                p.step = 0;
                vis[i][j] = 1;
                Q.push(p);
            }
            if(temp[i][j] == 'V'){
                s_x = i;
                s_y = j;
            }
            if(temp[i][j] == 'J'){
                e_x = i;
                e_y = j;
            }
        }
    }
     
    while(!Q.empty()){
        q = Q.front();
        Q.pop();
         
        for(k = 0; k < 4; k++){
            row = q.r + dir[k][0];
            col = q.c + dir[k][1];
             
            if(row >= 0 && row < n && col >= 0 && col < m && !vis[row][col]){
                vis[row][col] = 1;
                p.r = row;
                p.c = col;
                p.step = q.step + 1;
                if(map[row][col] > p.step)
                    map[row][col] = p.step;
                Q.push(p);
            }
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值