题目描述
一个点每过一个单位时间就会向四个方向扩散一个距离,如图。
两个点a、b连通,记作e(a,b),当且仅当a、b的扩散区域有公共部分。连通块的定义是块内的任意两个点u、v都必定存在路径e(u,a0),e(a0,a1),…,e(ak,v)。给定平面上的n给点,问最早什么时刻它们形成一个连通块。输入格式
第一行一个数n,以下n行,每行一个点坐标。
【数据规模】
对于20%的数据,满足1≤N≤5; 1≤X[i],Y[i]≤50;
对于100%的数据,满足1≤N≤50; 1≤X[i],Y[i]≤10^9。输出格式
一个数,表示最早的时刻所有点形成连通块。
输入样例
2
0 0
5 5输出样例
5
分析
曼哈顿最小生成树的模板题,只需将权值的累积转为求最小生成树的最大边即可,对于最大边的权重ans=x+y,则最大扩散时间即最大正方形边长=(ans+1)/2。
源程序
#include <bits/stdc++.h>
#define MAXN 55
using namespace std;
typedef long long ll;
struct Edge{
int u,v;
ll w;
bool operator <(const Edge a)const{
return w>a.w;
}
};
int n,x[MAXN],y[MAXN],father[MAXN];
ll getdis(int i,int j)
{
return abs(x[i]-x[j])+abs(y[i]-y[j]);
}
int find(int x)
{
if(x==father[x])return x;
return father[x]=find(father[x]);
}
int main()
{
while(~scanf("%d",&n)){
priority_queue<Edge> q;
for(int i=1;i<=n;i++)father[i]=i; //初始化
for(int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
for(int i=1;i<=n;i++) //建边
for(int j=i+1;j<=n;j++)
q.push(Edge{i,j,getdis(i,j)});
int k=0; //记录边数
ll ans=0; //记录权重
while(k<n-1){
int u=q.top().u,v=q.top().v;
int fu=find(u),fv=find(v);
ll w=q.top().w;
q.pop();
if(fu!=fv){ //两点还未联通,更新权值和边数
ans=max(ans,w);
k++;
father[fu]=fv;
}
}
printf("%ld\n",(ans+1)/2); //(ans+1)/2为最大正方形的边长
}
}