C - Survive the flood URAL - 2113

Survive the flood

原题链接:
http://acm.timus.ru/problem.aspx?space=1&num=2113

                     Time limit: 2.0 second
                     Memory limit: 256 MB

Every rabbit knows what to do in case of a flood. All you need to do is to get to a point above the water level and wait for Mazai. But when the actual flood happens, rabbits start to panic. That’s why we ask for your help to create an optimal evacuation plan for rabbits.Let’s describe the flood as a game between a rabbit and water. Game takes place in a rectangular grid with n rows and m columns. Let’s say that a point in a row i and a column j has coordinates (i, j). It is known, that for all 1 ≤ i ≤ n, 1 ≤ j ≤ m a cell with coordinates (i, j) has height hij. The rabbit starts at a point with coordinates (r1, c1), water starts at point with coordinates (r2, c2). Moreover, the rabbit has a property named jump height.The rabbit and water take turns, the rabbit makes the first move. After each move the rabbit either doesn’t move or jumps to any adjacent cell. Cells are adjacent, if they have a common side. In addition to this, the rabbit cannot move to a cell, which height exceeds the height of a current cell more than on jump height. Water just fills all the cells that have adjacent cell filled with water of greater or equal height. Both water and the rabbit should stay within the game grid.Rabbit can only survive in the cells not filled with water. The game doesn’t ever stop. Your task is to find the minimum jump height the rabbit needs to have in order to survive for infinite time.InputFirst line of input contains 2 integer numbers n and m separated with a space (1 ≤ n, m ≤ 100, n · m ≠1) — size of the game grid.The next n lines describe grid cells. Each of n strings contains m integer numbers, separated with a space hij (0 ≤ hij ≤ 105) — heights of cells.The next line contains two integer numbers r1 and c1, separated with a space (1 ≤ r1 ≤ n, 1 ≤ c1 ≤ m) — initial location of the rabbit.The last line contains two integers r2 and c2, separated with a space (1 ≤ r2 ≤ n, 1 ≤ c2 ≤ m) — initial location of water.It is guaranteed, that the rabbit and water start in different cells. Columns are numerated from 1 to mfrom left to right. Rows are numerated from 1 to n from top to bottom.OutputIf the rabbit cannot survive in any case, in a single line output -1.Otherwise, in a single line output a single number — the least jump height that rabbit should have in order to survive for infinite time.
这里插入图片描述
题目大意:
开始给出n行m 列的图上每个点的高度,兔子的位置和水的位置
兔子每次可以跳到上下左右格子(要跳到的目标格子和当前格子的高度差小于等于兔子的跳跃高度d),洪水每次可以蔓延到上下左右格子,(洪水的高度大于或等于要蔓延到的格子的高度。问兔子要是能安全(跳到比洪水高的格子),那兔子最小需要多少的跳跃高度?

解题思路:
1.先对洪水所在位置为根,进行bfs,这样可以算出洪水到达每个点的时间。
在这里插入图片描述
用一个mp[n][m]的数组记录洪水到达时间。首先初始化所有点为-1;令洪水所在点的时间为0,往上下左右搜索,如果能蔓延就更新时间。bfs完后,所有-1的点表示水蔓延不到的点。

2.二分法(O(logN))和对兔子路径bfs相结合
兔子跳跃高度最大为r=100000,最小为l=0,首先判断中点兔子能否安全,如果安全记录下高度,令r=mid-1,看能否找到更小的高度;如果不安全更新l=mid+1;

那判断在指定高度兔子能否幸存的方法就是对兔子的路径进行bfs,如果兔子能到达mp[i][j]==-1的点,那就安全了。另外对于bfs我们可以剪枝。如果之前已经访问过的点,用visit[n][m]数组记录下来,之后就不用再访问了。

#include<bits/stdc++.h>
using namespace std;

const int maxn=105;
int h[maxn][maxn];//原始数据
int mp[maxn][maxn];//水到达每个点的时间
int vis[maxn][maxn];
int vis2[maxn][maxn];
int n,m,r1,c1;//兔子
int r2,c2;//水
int dx[5]={1,0,-1,0},dy[5]={0,1,0,-1};
struct st//描述点的结构体
{
    int x;//行坐标
    int y;//列坐标
    int d;//高度
};

void bfs()
{
    int r,c,d;
    queue <st> que;
    que.push(st{r2,c2,0});
    while(!que.empty()){
    st t=que.front();
    que.pop();
    r=t.x;c=t.y;d=t.d;
    vis[r][c]=0;
    mp[r][c]=t.d;
    for(int i=0;i<4;i++){
        int x=r+dx[i],y=c+dy[i];
        if(x<=n&&x>=1&&y<=m&&y>=1&&h[x][y]<=h[r][c]&&vis[x][y]==0&&mp[x][y]==-1){
            vis[x][y]=1;
            que.push(st{x,y,d+1});
        }
      }
    }
}

int bfs2(int mid)
{
    int r,c,d;
    queue <st> que;
    que.push(st{r1,c1,0});
    while(!que.empty()){
        st t=que.front();
        que.pop();
        r=t.x;c=t.y;d=t.d;
        if(mp[r][c]==-1)return 1;
        vis[r][c]=1;//记录该点已经走过了,下次就不要走了
        vis2[r][c]=0;//记录该店在不在队列里面,现在出队了
        for(int i=0;i<4;i++)
        {
            int x=r+dx[i],y=c+dy[i];
            if(x<=n&&x>=1&&y>=1&&y<=m&&vis[x][y]==0&&vis2[x][y]==0&&h[x][y]<=mid+h[r][c]&&(mp[x][y]==-1||mp[x][y]>d+1)){
               que.push(st{x,y,d+1});
               vis2[x][y]=1;
            }
        }
    }
    return 0;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&h[i][j]);
    scanf("%d%d",&r1,&c1);
    scanf("%d%d",&r2,&c2);
    memset(mp,-1,sizeof(mp));
    bfs();
    int ans=-1;
    int l=0,r=100000;
    while(l<=r) {
        int mid=(l+r)>>1;
        memset(vis,0,sizeof(vis));
        memset(vis2,0,sizeof(vis2));
        if(bfs2(mid)){
            ans=mid;
            r=mid-1;
        }
        else{
            l=mid+1;
        }
    }
    printf("%d\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值