汽车拉力比赛
题目描述
博艾市将要举行一场汽车拉力比赛。
赛场凹凸不平,所以被描述为 N ∗ M N*M N∗M 的网格来表示海拔高度 ( 1 ≤ M , N ≤ 500 ) (1 \leq M,N \leq 500) (1≤M,N≤500),每个单元格的海拔范围在 0 0 0 到 1 0 9 10^9 109 之间。
其中一些单元格被定义为路标。组织者希望给整个路线指定一个难度系数 D D D,这样参赛选手从任一路标到达别的路标所经过的路径上相邻单元格的海拔高度差不会大于 D D D 。也就是说这个难度系数 D D D 指的是保证所有路标相互可达的最小值。任一单元格和其东西南北四个方向上的单元格都是相邻的。
输入格式
第 1 1 1 行两个整数 M M M 和 N N N。第 2 2 2 行到第 M + 1 M+1 M+1 行,每行 N N N 个整数描述海拔高度。第 2 + M 2+M 2+M 行到第 1 + 2 M 1+2M 1+2M
行,每行 N N N 个整数,每个数非 0 0 0 即 1 1 1, 1 1 1 表示该单元格是一个路标。
输出格式
一个整数,即赛道的难度系数 D D D。
样例 #1
样例输入 #1
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
样例输出 #1
21
思路
- 首先,难度值最大值最小——用二分。
- 其次,其次,题目说相邻的高度差不大于D,而且有规定从路标到路标,因此这里就是联通性问题——并查集。
- 最后检查每个路标是否联通。
代码
//首先,难度值最大值最小——用二分
//其次,题目说相邻的高度差不大于D,而且有规定从路标到路标,因此这里就是联通性问题——并查集
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define x first
#define y second
#define int long long
using namespace std;
typedef pair<int,int>PII;
const int N = 510;
int p[N*N];
int w[N][N];
int n,m;
PII e[N*N];
int cnt;
bool st[N][N];
int mark[N][N],idx;//类似拯救大兵瑞恩的那道题思路
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int find(int x){
if(x!=p[x])p[x]=find(p[x]);
return p[x];
}
bool check(int mid){
for(int i=1;i<=n*m;i++)p[i]=i;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=0;k<4;k++){
int a=i+dx[k],b=j+dy[k];
if(a<1||b<1||a>n||b>m)continue;
if(abs(w[i][j]-w[a][b])>mid)continue;
p[find(mark[i][j])]=find(mark[a][b]);
}
}
}
for(int i=1;i<cnt;i++){
if(find(mark[e[i].x][e[i].y])!=find(mark[e[i-1].x][e[i-1].y])){
return false;
}
}
return true;
}
signed main(){
cin>>n>>m;
int r=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
mark[i][j]=++idx;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>w[i][j];
r=max(r,w[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x;
cin>>x;
if(x){
e[cnt++]={i,j};
}
}
}
int l=-1;
r++;
while(l+1!=r){
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid;
}
cout<<r;
return 0;
}