扩散
题目描述
一个点每过一个单位时间就会向四个方向扩散一个距离,如图。
两个点 a a a 、 b b b 连通,记作 e ( a , b ) e(a,b) e(a,b),当且仅当 a , b a,b a,b 的扩散区域有公共部分。连通块的定义是块内的任意两个点 u , v u,v u,v 都必定存在路径 e ( u , a 0 ) , e ( a 0 , a 1 ) , ⋯ , e ( a k , v ) e(u,a_0),e(a_0,a_1),\cdots,e(a_k,v) e(u,a0),e(a0,a1),⋯,e(ak,v)。给定平面上的 n n n 给点,问最早什么时刻它们形成一个连通块。
输入格式
第一行一个数 n n n,以下 n n n 行,每行一个点坐标。
输出格式
一个数,表示最早的时刻所有点形成连通块。
样例 #1
样例输入 #1
2
0 0
5 5
样例输出 #1
5
提示
数据范围及约定
对于 20 % 20\% 20% 的数据,满足 1 ≤ N ≤ 5 ; 1 ≤ X i , Y i ≤ 50 1 \le N \le 5;1 \le X_i,Y_i \le 50 1≤N≤5;1≤Xi,Yi≤50。
对于 100 % 100\% 100% 的数据,满足 1 ≤ N ≤ 50 1 \le N \le 50 1≤N≤50, 1 ≤ X i , Y i ≤ 1 0 9 1 \le X_i,Y_i \le 10^9 1≤Xi,Yi≤109。
思路
对于连通性问题,我们往往可以跟并查集联系起来,这道题说了只能沿四个方向走(有点像菱形扩散),我们可以联想到曼哈顿距离,又因为本道题每个点都可以扩散,因此对于样例,不止(0,0)可以扩散,(5,5)也可以扩散。然后当我们假设一个答案时间,如果两个点的曼哈顿距离<=两倍的我们假设的时间(问题:这里为什么是两倍呢?因为例如样例:两边都可以扩散,因此相对距离就得是2*t),而且二者还不在同一个集合中(也就是说并查集在拥有同一个祖先节点),我们就将二者放入同一集合中。
代码
//我感觉连通性往往跟并查集有关,然后我们可以试着给定答案,看看答案是否满足
//这道题有点曼哈顿距离给我的感觉(因为它只能走四个方位,不很想曼哈顿距离不)
#include<iostream>
#include<algorithm>
#include<cstring>
#define x first
#define y second
using namespace std;
typedef pair<int,int>PII;
const int N = 55,M = 1e9;
int p[N];
PII w[N];
int n;
int find(int x){
if(x!=p[x])p[x]=find(p[x]);
return p[x];
}
bool check(int x){
for(int i=1;i<=n;i++)p[i]=i;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(abs(w[i].x-w[j].x)+abs(w[i].y-w[j].y)<=2*x&&find(i)!=find(j)){
p[find(i)]=find(j);
}
}
}
int cnt=0;
for(int i=1;i<=n;i++){
if(i==find(i))cnt++;
}
return cnt==1;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>w[i].x>>w[i].y;
int l=-1,r=M+1;
//我们二分时间
while(l+1!=r){
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid;
}
cout<<r;
return 0;
}