题目描述
一个点每过一个单位时间就会向 4 个方向扩散一个距离,如图所示:两个点 a 、b 连通,记作 e(a,b),当且仅当 a 、b 的扩散区域有公共部分。连通块的定义是块内的任意两个点 u、v 都必定存在路径 e(u,a0),e(a0,a1),…e(ak,v)。
给定平面上的 n 个点,问最早什么时候它们形成一个连通块。
输入格式
第一行一个数 n ,以下 n 行,每行一个点坐标。
输出格式
输出仅一个数,表示最早的时刻所有点形成连通块。
样例
Input Output
2
0 0
5 5
5
数据范围与提示
对于 20% 的数据,满足 1≤n≤5,1≤Xi,Yi≤50;
对于 100% 的数据,满足 1≤n≤50,1≤Xi,Yi≤10^9。
思路:
连通块,想到用并查集。求解扩散形成连通块的最早时间,在0-1e9内用二分搜索。因为扩散是所有点同时进行,所以对于任意两点,判断2*t>=abs(x[i]-x[j])+abs(y[i]-y[j])就可知这两点是否直接相联系,若联系就录入并查集。
代码:
#include <bits/stdc++.h>
#define N 1e9 //10亿
using namespace std;
long long int x[55],y[55];
int dat[55];
int n;
int find(int p){
if(dat[p]==p) return p;
else return find(dat[p]);
}
bool conn(int t){
//并查集初始化
for(int i=1;i<=n;i++){
dat[i]=i;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(2*t>=abs(x[i]-x[j])+abs(y[i]-y[j])){
int a=find(i),b=find(j);
if(a!=b) dat[a]=b; //若根不同则置换
}
}
}
//形成连通块之后应该只有一个根
int root=0;
for(int i=1;i<=n;i++){
if(dat[i]==i) root++;
}
if(root==1) return true;
else return false;
}
int main() {
cin>>n;
if(n==1){
cin>>x[0]>>y[0];
cout<<0;
return 0;
}
for(int i=1;i<=n;i++){
cin>>x[i]>>y[i];
}
int l=0,u=N,ans;
//二分搜索答案
while(l<=u){
int m=(l+u)/2;
if(conn(m)){
u=m-1;
ans=m;
}
else l=m+1;
}
printf("%d",ans);
return 0;
}