最近点对问题

分而治之

题目来源:Quoit Design

Problem Description
Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded.
In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it can only encircle one toy at a time. On the other hand, to make the game look more attractive, the ring is designed to have the largest radius. Given a configuration of the field, you are supposed to find the radius of such a ring.

Assume that all the toys are points on a plane. A point is encircled by the ring if the distance between the point and the center of the ring is strictly less than the radius of the ring. If two toys are placed at the same point, the radius of the ring is considered to be 0.

Input
The input consists of several test cases. For each case, the first line contains an integer N (2 <= N <= 100,000), the total number of toys in the field. Then N lines follow, each contains a pair of (x, y) which are the coordinates of a toy. The input is terminated by N = 0.

Output
For each test case, print in one line the radius of the ring required by the Cyberground manager, accurate up to 2 decimal places.

Sample Input

2
0 0
1 1
2
1 1
1 1
3
-1.5 0
0 0
0 1.5
0

Sample Output

0.71
0.00
0.75

题目大意是从所有的点集中找到最短距离的二分之一即可
刚刚拿到题,直接想到的就是暴力求解,果然还是头脑简单了点,这样做,是可以得解,但是必然exceed running time
查找了一下资料,发现在一本书上有记载一种算法,是用分治的思想解决这类题型的
思想如下:
先将所有点按照x的大小进行排序,再根据x方向将平面中的分成左右两个部分,即Left,Right,并且要求这两个部分的点的个数大致相同,在递归得到了minLeft,minRight后,我们先得到一个可能解ans=min( minLeft,minRight ),但实际上,可能解还存在与Left和Right的中间那个部分,当然,只有这些点对的距离小于ans,才会成为可能解
但是,此处距离的判断也是一个问题,因为这里很有可能会超时
可以反推
要使条件成立,那么可能解的点的横坐标与中轴横坐标差的绝对值必然是小于ans的
最后,再按照y的大小进行升序排序,同理
可能解的纵坐标与中轴纵坐标差的绝对值必然也是小于ans的
书上写了该算法的时间复杂度为O(nlogn)

知道核心思想后的代码

很奇怪为什么WA

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;

struct Point {
	double x;
	double y;
}p[100005], tmp[100005];
double Solution(int left,int right);
double Dis(Point& p1, Point& p2) {
	return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y)*(p1.y-p2.y));
}
double min3(double a, double b, double c) {
	double pre = min(a, b);
	return min(pre, c);
}
bool cmp(Point& p1, Point& p2) {
	if (p1.x == p2.x) {
		return p1.y < p2.y;
	}
	return p1.x < p2.x;
}
bool cmpY(Point& p1, Point& p2) {
	if (p1.y == p2.y) {
		return p1.x < p2.x;
	}
	return p1.y < p2.y;
}
int main() {
	int n;
	scanf("%d", &n);
	while (n != 0) {
		memset(p, 0, sizeof(p));
		for (int i = 0; i < n; i++) {
			scanf("%lf %lf", &p[i].x, &p[i].y);
		}
		sort(p, p + n, cmp);
		printf("%.2lf\n", Solution(0, n - 1)/2);
		scanf("%d", &n);
	}
	return 0;
}
double Solution(int left,int right) {
	if (left == right)return 0;
	else if ((right - left) == 1) { //2points
		return Dis(p[left], p[right]);
	}
	else if ((right - left) == 2) { //3points
		return min3(Dis(p[left], p[left + 1]), Dis(p[left], p[right]), Dis(p[left + 1],
			p[right]));
	}
	int mid = (left + right) >> 1;
	int num = 0;
	double ans = min(Solution(left, mid), Solution(mid + 1, right));
	for (int i = left; i <= mid; i++) {
		if (fabs(p[i].x - p[mid].x) < ans) {
			tmp[num++] = p[i];
		}
	}
	sort(tmp, tmp + num, cmpY);
	for (int i = 0; i < num; i++) {
		for (int j = i+1; j <num; j++) {
			if (tmp[j].y - tmp[i].y < ans) {
				ans = min(ans, Dis(p[i], p[j]));
			}
			else break;
		}
	}
	return ans;
}

最终AC代码

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;

struct Point {
	double x;
	double y;
}p[100005]/*, tmp[100005]*/;
int tmp[100005];
double Solution(int left,int right);
double Dis(Point& p1, Point& p2) {
	return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y)*(p1.y-p2.y));
}
double min3(double a, double b, double c) {
	double pre = min(a, b);
	return min(pre, c);
}
bool cmp(Point& p1, Point& p2) {
	if (p1.x == p2.x) {
		return p1.y < p2.y;
	}
	return p1.x < p2.x;
}
bool cmpY(int p1,int p2) {
	if (p[p1].y == p[p2].y) {
		return p[p1].x < p[p2].x;
	}
	return p[p1].y < p[p2].y;
}
int main() {
	int n;
	scanf("%d", &n);
	while (n != 0) {
		memset(p, 0, sizeof(p));
		for (int i = 0; i < n; i++) {
			scanf("%lf %lf", &p[i].x, &p[i].y);
		}
		sort(p, p + n, cmp);
		bool flag = true;
		for (int i = 0; i < n-1; i++) {
			if (p[i].x == p[i + 1].x && p[i].y == p[i + 1].y) {
				flag = false;
				break;
			}
		}
		if (!flag)cout << "0.00\n";
		else printf("%.2lf\n", Solution(0, n - 1)/2);
		scanf("%d", &n);
	}
	return 0;
}
double Solution(int left,int right) {
	if (left == right)return 0;
	else if ((right - left) == 1) { //2points
		return Dis(p[left], p[right]);
	}
	else if ((right - left) == 2) { //3points
		return min3(Dis(p[left], p[left + 1]), Dis(p[left], p[right]), Dis(p[left + 1],
			p[right]));
	}
	int mid = (left + right) >> 1;
	int num = 0;
	double ans = min(Solution(left, mid), Solution(mid + 1, right));
	for (int i = left; i <= mid; i++) {
		if (fabs(p[i].x - p[mid].x) < ans) {
			tmp[num++] = i;
		}
	}
	sort(tmp, tmp + num, cmpY);
	for (int i = 0; i < num; i++) {
		for (int j = i+1; j <num; j++) {
			if (p[tmp[j]].y - p[tmp[i]].y < ans) {
				ans = min(ans, Dis(p[tmp[i]], p[tmp[j]]));
			}
			else break;
		}
	}
	return ans;
}

这段代码其实是有借鉴人家的,但是感觉核心理念是一样的啊,只不过将结构体数组换成了int类型的数组,是因为结构体在赋值的时候会消耗大量时间吧?

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值