题目描述
滑雪场可以看成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)