1.【题目描述】:
一个点每过一个单位时间就会向四个方向扩散一个距离,如图。
两个点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
2.解析:
首先我们要明白此点距离与时间的关系,不难发现此距离即为点到原点的曼哈顿距离(读者自证),所以我们只需枚举时间,让其时间满足其时间>=曼哈顿距离即可。读者需要注意,两点的距离最远不会超过2倍时间,否则将不被满足联通,这很好理解:因为最极端的情况即为两点对立,且点到原点距离为最大时间,此时距离为2*时间。
知道以上几点我们不难想到用二分枚举时间,求出最小时间且满足距离不会超过2倍时间,值得一提的是这里可以用并查集来联通,当然也可以定义一个标记数组来做,如:
int step = 0, sum = 1, flag[1005] = { };
b[1] = 1;
flag[1] = 1;
while(step != sum) {//当等于是即有一组不满足跳出
step++;
for(int i = 1;i <= n; i++) {
if(flag[i]) {//若被判断了就不管了
continue;
}
if(m[b[step]][i] <= 2 * s) {
flag[i] = 1;
b[++sum] = i;
}
}
}
3.代码:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int n, m[1005][1005], b[1005];
struct jj{
int x, y;
}a[10005];
void manhadun() {
for(int i = 1;i < n; i++) {
for(int j = i + 1;j <= n; j++) {
m[j][i] = m[i][j] = abs(a[i].x - a[j].x) + abs(a[i].y - a[j].y);
}
}
}
int cheak(long long s) {
int step = 0, sum = 1, flag[1005] = { };
b[1] = 1;
flag[1] = 1;
while(step < sum) {
step++;
for(int i = 1;i <= n; i++) {
if(flag[i]) {
continue;
}
if(m[b[step]][i] <= 2 * s) {
flag[i] = 1;
b[++sum] = i;
}
}
}
return sum == n;
}
int main() {
scanf("%d", &n);
for(int i = 1;i <= n; i++) {
scanf("%d %d", &a[i].x, &a[i].y);
}
manhadun();
int l = 0, r = 1e9 + 5, mid, k;
while(l <= r) {
mid = l + ((r - l) / 2);
if(cheak(mid)) {
r = mid - 1;
}
else{
l = mid + 1;
}
}
printf("%d", l);
return 0;
}