poj3714——最近点问题

我们先来看一个例题。给定n个点的坐标,求其中最近的两个点的距离。

朴素做法是O(n²)的,这里我们采用分治的思想来解题。所谓分治,即分开处理。我们先按横坐标进行排序,这样可以使点是从左到右分布的。接着,把这些点分为两部分(当然是对半分了),分别求出这两部分的答案。这时你可能要问了,万一答案是从这两部分里各挑一个点呢?emmm我觉得十分有道理,于是……我们要不暴力枚举跨块的吧!(你看你看分块的时候都这么做!!!)(众人:呸。)这样的复杂度显然是不(退)对(化)的。

由于前面我所做的伟大决定——分治,已经为我得出了一个答案,它(记为min1吧)不一定是最佳的,但是答案一定小于等于它。因此我们可以只暴力枚举一部分(所谓剪枝)。只看横坐标,我们把所有距离a[mid]小于min1的都留下。(写成表达式就是 abs(a[i].x - a[mid].x) < min1)然后呢,对这些点按照纵坐标进行排序。(没错没错相信我,这是为了更大的剪枝!)然后进行平方的循环。对于一个点,一旦这个y的距离都超过了min1(min1我们是要更新的,而且这并不妨碍我们判断是否break),那后面的自然没必要看了。

我一直觉得这个方法很玄(悬)。

至于poj3714,加个标记,判断是否属于一类再返回就得了。附上代码。

#include <cstdio>
#include <cmath>
#include <algorithm>
#define N 100010
const double inf = 999999999;
using namespace std;
struct node {double x, y; bool flag;}a[2*N]; int T, n, q[2*N];
inline bool mycmp(node a, node b) {return (a.x == b.x)?(a.y < b.y):(a.x < b.x);}
inline bool mycmp2(int x, int y) {return a[x].y < a[y].y;}
inline double mymin(double x, double y) {return (x < y)?x:y;}
inline double myabs(double x) {return (x < 0)?(0 - x):x;}
inline double dis(double x1, double y1, double x2, double y2) {return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));}
double getans(int l, int r) {
	if(l + 2 == r) return mymin((a[l].flag != a[l + 1].flag)?(dis(a[l].x, a[l].y, a[l + 1].x, a[l + 1].y)):inf, mymin((a[l].flag != a[r].flag)?(dis(a[l].x, a[l].y, a[r].x, a[r].y)):inf, (a[l + 1].flag != a[r].flag)?(dis(a[l + 1].x, a[l + 1].y, a[r].x, a[r].y)):inf));
	if(l + 1 == r) return (a[l].flag != a[r].flag)?dis(a[l].x, a[l].y, a[r].x, a[r].y):inf;
	int mid = (l + r)>>1;
	double min1 = mymin(getans(l, mid), getans(mid + 1, r));
	int cnt = 0;
	for(int i = l; i <= r; ++i)
		if(myabs(a[i].x - a[mid].x) <= min1) q[++cnt] = i;
	sort(q+1, q+cnt+1, mycmp2);
	for(int i = 1; i < cnt; ++i)
		for(int j = i + 1; j <= cnt; ++j)
			if(a[q[i]].flag != a[q[j]].flag) {
				if(a[q[j]].y - a[q[i]].y >= min1) break;
				min1 = min(min1, dis(a[q[i]].x, a[q[i]].y, a[q[j]].x, a[q[j]].y));
			}
	return min1;
}
int main() {
	scanf("%d", &T);
	for(int cases = 1; cases <= T; ++cases) {
		scanf("%d", &n);
		for(int i = 1; i <= n; ++i) scanf("%lf%lf", &a[i].x, &a[i].y), a[i].flag = true;
		for(int i = n + 1; i <= n * 2; ++i) scanf("%lf%lf", &a[i].x, &a[i].y), a[i].flag = false;
		sort(a+1, a+2*n+1, mycmp);
		printf("%.3f\n", getans(1, 2*n));
	}
	return 0;
}
我就不明白了!!!为什么poj好多题必须"%.3f"!!!WA了半天!!!
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值