扩散题解

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;
} 

猜你喜欢

转载自blog.csdn.net/cqbz_lipengcheng/article/details/107244930
今日推荐