题目描述
一个点每过一个单位时间就会向 4 个方向扩散一个距离,如图所示:两个点 a 、b 连通,记作 e(a,b),当且仅当 a 、b
的扩散区域有公共部分。连通块的定义是块内的任意两个点 u、v 都必定存在路径 e(u,a0),e(a0,a1),…e(ak,v)。
给定平面上的 n 个点,问最早什么时候它们形成一个连通块。
输入格式
第一行一个数 n ,以下 n 行,每行一个点坐标。
输出格式
输出仅一个数,表示最早的时刻所有点形成连通块。
样例
输入
2
0 0
5 5
输出
5
AC代码
#include<bits/stdc++.h>
using namespace std;
struct point{
int x;
int y;
}a[55];
int dis[1005][1005];
double mt(point,point);
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=mt(a[i],a[j]);
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(max(dis[i][k],dis[k][j]),dis[i][j]);
}
}
}
int ans=-1e10;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans=max(ans,dis[i][j]);
}
}
cout<<ans;
return 0;
}
double mt(point m,point n){
return ceil((abs(m.x-n.x)+abs(m.y-n.y))/2.0);
}
详解
Floyd算法
求多元最短路径
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(max(dis[i][k],dis[k][j]),dis[i][j]);
}
}
}
时间复杂度为O(n^3)
代码解析
mt函数
double mt(point m,point n){
return ceil((abs(m.x-n.x)+abs(m.y-n.y))/2.0);
}
用来求两点间的扩散成连通块的时间(忽略中间的点)
ceil是向上取整函数
第二个大循环
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=mt(a[i],a[j]);
}
}
先定义一个初值,即两点间最初的权值(扩散成连通块的时间)
第四个大循环
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans=max(ans,dis[i][j]);
}
}
因为任意两点扩散成连通块的最小时间肯定有最大值和最小值
所以最大的最小时间即为最后一个连成连通块的时间
此时其他点都已经连通完了
所以这里ans求最大值
tips
int ans=-1e10;
这里赋值成了-1*10^10
如果无法理解可以换成常见的
int ans=-0x3f3f3f;
评价
Floyd算法在这个题的解题思路中算是较好理解的了
并且即使是3层循环的dp也根本不会超时
还有其他解题思路,如Kruscal算法(想一想,为什么)