滑雪场的高度差----分治+BFS

题目描述

滑雪场可以看成M x N的网格状山地(1 <= M,N <= 500),每个网格是一个近似的平面,具有水平高度值在0 .. 1,000,000,000米的范围内。

某些网格被指定为关键网格。当两个相邻网格之间的高度差的绝对值不超过某个参数D时,就可以相互到达。相邻关系是指某个格子的东、西、南、北的格子。

显然,当D不断减小时,原本可以相互到达的相邻格子就不能到达了。

滑雪赛的组委会想知道,为了保证各个关键网格之间彼此连通,最小的D是多少?

 

输入

 第1行:2个整数M和N

接下来M行,每行N个整数,表示各网格的高度

接下来M行,每行N个0或者1,1表示关键网格

输出

 第1行:1个整数,表示最小的D

样例输入

Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

3 5
20 21 18 99 5
19 22 20 16 26
18 17 40 60 80
1 0 0 0 1
0 0 0 0 0
0 0 0 0 1

样例输出

21

题解

这道题的思路很简单也很容易想到简直是智障题,因为几乎在任何情况下,都可以知道答案D的搜索方向。当(当前的D可以使)所有的关键网格都可相连时,真正的答案必定≤D,反之如果不能相连,那么说明路径上肯定有高度过高的“断崖”,D就需要增加。

↖题中样例

这里就需要用到分治法了,把查找范围定为(l~r),取mid=(l+r)/2中间值当做D判断符不符合,用上方法不断取前后两个区间其一。

至于判断能否相连,用一个BFS宽搜就可以了,当遍历到所有关键网格时,就返回true,每次把前后左右高度差≤mid的小山入队。如遍历结束都没遍历到所有关键网格,就返回fulse。

代码如下,以理解的就不用看了。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,i,j,k,h[505][505],l,r,mid,di[4][2]={{1,0},{0,-1},{-1,0},{0,1}};
bool v[505][505],f[505][505];
struct itn{
    int x,y;
    itn(){}
    itn(int X,int Y){
        x=X,y=Y;
    }
}in;
inline int read(){
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
inline int abss(int nm){
    return nm>0?nm:-nm;
}
inline bool bfs(int d){
    int Sum=0;
    queue<itn>p;
    memset(f,0,sizeof(f));
    p.push(in);
    while(!p.empty()){
        int xx=p.front().x,yy=p.front().y;
        p.pop();
        if(xx<1||xx>n||yy<1||yy>m)continue;
        if(f[xx][yy])continue;
        f[xx][yy]=1;
        if(v[xx][yy])Sum++;
        if(Sum==k)return 1;
        for(int o=0;o<4;o++){
            int xi=xx+di[o][0],yi=yy+di[o][1];
            if(abss(h[xi][yi]-h[xx][yy])<=d)p.push(itn(xi,yi));
        }
    }
    return 0;
}
int main()
{
    n=read(),m=read();
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++){
            h[i][j]=read();
            r=max(r,h[i][j]);
        }
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++){
            v[i][j]=read();
            if(v[i][j])k++,in=itn(i,j);
        }
    mid=(l+r)/2;
    while(r>=l){
        if(bfs(mid))r=mid-1;
        else l=mid+1;
        mid=(l+r)/2;
    }
    printf("%d",l);
    putchar('\n');
    return 0;
}

欢迎关注我的博客 偶耶(xiong j x)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值