返回顶部

平面最近点对

问题描述:给你\(n\)个在二维平面上的点,让你求任意两个点之间的欧几里得距离的最小值

P1257 平面上的最接近点对

此题\(2 \leq n \leq 10^4\) ,所以可以暴力枚举任意两个点求距离然后取最小值

时间复杂度:\(O(n^2)\) 可以通过此题

参考代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e4 + 5;
ll px[N], py[N];
int n;
long long mx = 100000000000;
ll dis(int i, int j) {
	return (px[i] - px[j]) * (px[i] - px[j]) + (py[i] - py[j]) * (py[i] - py[j]);
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> px[i] >> py[i];
		for (int j = 1; j < i; ++j) mx = min(mx, dis(i, j));
	}
	printf("%.4f", sqrt(mx));
	return 0;
}
P1429 平面最近点对(加强版)

此题\(2 \leq n \leq 2e5\) ,显然需要更优复杂度的做法-分治,此处可以去参考平面最近点对讲解的分治做法,复杂度为:\(O(nlog^2n)\)

非分治做法也可参考上述链接内的相关部分

参考代码:

#include<bits/stdc++.h>

struct Point {
	double x, y;
	void read() {
		scanf("%lf%lf", &x, &y);
		return;
	}
	Point(double _x = 0.0, double _y = 0.0) :x(_x), y(_y) {}
	bool operator < (const Point& a) const {
		return y < a.y;
	}
};
double res;
void update(const Point& a, const Point& b) {
	double dx = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
	res = std::min(res, dx);
	return;
}
const int N = 1e6 + 5;
Point points[N], t[N];

void solve(int lr, int rs) {
	if (lr >= rs) return;
	int mid = lr + rs >> 1;
	double midx = points[mid].x;
	solve(lr, mid); solve(mid + 1, rs);
	int l = lr, r = mid + 1, k = 0;
	while (l <= mid && r <= rs) {
		if (points[l] < points[r]) t[++k] = points[l++];
		else t[++k] = points[r++];
	}
	while (l <= mid) t[++k] = points[l++];
	while (r <= rs) t[++k] = points[r++];
	k = 1;
	for (int i = lr; i <= rs; ++i) points[i] = t[k++];
	int size = 0;
	for (int i = lr; i <= rs; ++i) {
		if (std::abs(points[i].x - midx) < res) {
			for (int j = size - 1; j >= 0 && points[i].y - t[j].y < res; --j)
				update(points[i], t[j]);
			t[size++] = points[i];
		}
	}
	return;
}

int n;

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) points[i].read();
	std::sort(points + 1, points + 1 + n, [&](const Point& a, const Point& b) {
		return a.x < b.x || (a.x == b.x && a.y < b.y);
		});
	res = 1e20;
	solve(1, n);
	printf("%.4lf\n", res);
	return 0;
}
P7883 平面最近点对(加强加强版)

此题\(2 \leq n \leq 4 \times 10 ^ 5\),但时限只有\(350ms\),所以只能使用上面的\(O(nlog^2n)\)做法,注意这题输出的是\(D^2\),且这题距离最大值为\(2 \times 10^{14}\)\(double\)类型精度的表示范围内,故只需要在上述代码的输出部分进行修改即可。(我使用不损失精度的记录答案的方法\(TLE\)了)

参考代码:

#include<bits/stdc++.h>

struct Point {
	double x, y;
	void read() {
		scanf("%lf%lf", &x, &y);
		return;
	}
	Point(double _x = 0.0, double _y = 0.0) :x(_x), y(_y) {}
	bool operator < (const Point& a) const {
		return y < a.y;
	}
};
double res;
void update(const Point& a, const Point& b) {
	double dx = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
	res = std::min(res, dx);
	return;
}
const int N = 1e6 + 5;
Point points[N], t[N];

void solve(int lr, int rs) {
	if (lr >= rs) return;
	int mid = lr + rs >> 1;
	double midx = points[mid].x;
	solve(lr, mid); solve(mid + 1, rs);
	int l = lr, r = mid + 1, k = 0;
	while (l <= mid && r <= rs) {
		if (points[l] < points[r]) t[++k] = points[l++];
		else t[++k] = points[r++];
	}
	while (l <= mid) t[++k] = points[l++];
	while (r <= rs) t[++k] = points[r++];
	k = 1;
	for (int i = lr; i <= rs; ++i) points[i] = t[k++];
	int size = 0;
	for (int i = lr; i <= rs; ++i) {
		if (std::abs(points[i].x - midx) < res) {
			for (int j = size - 1; j >= 0 && points[i].y - t[j].y < res; --j)
				update(points[i], t[j]);
			t[size++] = points[i];
		}
	}
	return;
}

int n;

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) points[i].read();
	std::sort(points + 1, points + 1 + n, [&](const Point& a, const Point& b) {
		return a.x < b.x || (a.x == b.x && a.y < b.y);
		});
	res = 1e20;
	solve(1, n);
	printf("%.0lf\n", res * res);
	return 0;
}

同类型的习题可以参考上述的 平面最近点对 的链接内的习题

其它习题:

CF429D Tricky Function

题目描述:给定长度为\(n\)的序列\(a\),定义函数\(f(i , j) = (i - j)^2 + g(i , j)^2\) , 其中\(g(i , j) = preSum_i - preSum_j\)

\(min_{i \neq j} f(i , j)\)

\[2 \leq n \leq 10^5 , |a_i| \leq 10^4 \]

思路:根据题面如果把下标和对应的前缀表示成点\((i , preSum_i)\),那么问题就是求任意两点距离的平方的最小值,套用上述模板即可

参考代码:

#include<bits/stdc++.h>

struct Point {
	double x, y;
	void read() {
		scanf("%lf%lf", &x, &y);
		return;
	}
	Point(double _x = 0.0, double _y = 0.0) :x(_x), y(_y) {}
	bool operator < (const Point& a) const {
		return y < a.y;
	}
};
double res;
void update(const Point& a, const Point& b) {
	double dx = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
	res = std::min(res, dx);
	return;
}
const int N = 1e6 + 5;
Point points[N], t[N];

void solve(int lr, int rs) {
	if (lr >= rs) return;
	int mid = lr + rs >> 1;
	double midx = points[mid].x;
	solve(lr, mid); solve(mid + 1, rs);
	int l = lr, r = mid + 1, k = 0;
	while (l <= mid && r <= rs) {
		if (points[l] < points[r]) t[++k] = points[l++];
		else t[++k] = points[r++];
	}
	while (l <= mid) t[++k] = points[l++];
	while (r <= rs) t[++k] = points[r++];
	k = 1;
	for (int i = lr; i <= rs; ++i) points[i] = t[k++];
	int size = 0;
	for (int i = lr; i <= rs; ++i) {
		if (std::abs(points[i].x - midx) < res) {
			for (int j = size - 1; j >= 0 && points[i].y - t[j].y < res; --j)
				update(points[i], t[j]);
			t[size++] = points[i];
		}
	}
	return;
}

int n;
int a[N];
int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), a[i] += a[i - 1];
	for (int i = 1; i <= n; ++i) {
		points[i].x = i;
		points[i].y = a[i];
	}
	std::sort(points + 1, points + 1 + n, [&](const Point& a, const Point& b) {
		return a.x < b.x || (a.x == b.x && a.y < b.y);
		});
	res = 1e20;
	solve(1, n);
	printf("%.0lf\n", res * res);
	return 0;
}
posted @ 2021-12-23 20:16  cherish-lgb  阅读(37)  评论(0编辑  收藏  举报