POJ 3714 Raid 平面最近点对

题目大意:给出两个集合的点,问这两个集合之间最近的点对的距离是多少。

思路:先要知道平面最近点对的分治算法,剩下的就简单了,只需要在更新答案的时候判断一下两个点是否属于两个集合就可以了。

分治算法总是十分神奇的。

对于平面最近点对,首先按照x坐标排序,然后递归进行分治,每次分治时,先获得分治得到的结果,然后按照这个结果来计算本区间。由于我们只需要计算答案小于这个结果的点对就行了,其中(l,mid)和(mid + 1,r)我们已经得到答案,只需要统计一个点在(l,mid),另一个点在(mid + 1,r)的所有点对了。但是这还是很大。

有一个强剪枝,设立中轴为(X[mid] + X[mid + 1]) / 2,我们只需要统计在这个中轴两侧不超过之前算过的最小值的点就可以了,因为其他的点对不可能更新答案。

还有一个剪枝,每次找到这些点之后,再按照y坐标排序,之后发现y坐标相差超过之前算过的最小值的点对也肯定不能更新答案,对于一个点来说能够更新答案的点在另一侧是一个单调的区间,只需要一个指针扫一下就行了。

CODE:

#include <cmath>
#include <cstdio>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 200010
#define INF 1e15
using namespace std;

struct Point{
	double x,y;
	bool p;

	bool operator <(const Point &a)const {
		return x < a.x;
	}
	void Read(bool _) {
		scanf("%lf%lf",&x,&y);
		p = _;
	}
}point[MAX],L[MAX],R[MAX];

int points;

inline double Calc(const Point &p1,const Point &p2)
{
	return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}

bool cmp(const Point &p1,const Point &p2)
{
	return p1.y < p2.y;
}

double Solve(int l,int r)
{
	double re = INF;
	if(r - l <= 2) {
		for(int i = l; i <= r; ++i)
			for(int j = i + 1; j <= r; ++j)
				if(point[i].p != point[j].p)
					re = min(re,Calc(point[i],point[j]));
		return re;
	}
	int mid = (l + r) >> 1;
	re = min(re,Solve(l,mid));
	re = min(re,Solve(mid + 1,r));
	double x = (point[mid].x + point[mid + 1].x) / 2.0;
	int pl = mid,pr = mid + 1;
	int ltop = 0,rtop = 0;
	while(x - point[pl].x <= re && pl >= l)	L[++ltop] = point[pl--];
	while(point[pr].x - x <= re && pr <= r)	R[++rtop] = point[pr++];
	sort(L + 1,L + ltop + 1,cmp);
	sort(R + 1,R + rtop + 1,cmp);
	int start = 1;
	for(int i = 1; i <= ltop; ++i) {
		while(L[i].y - R[start].y > re)	++start;
		for(int j = start; R[j].y - L[i].y < re && j <= rtop; ++j)
			if(L[i].p != R[j].p)
				re = min(re,Calc(L[i],R[j]));
	}
	return re;
}

int main()
{
	int T;
	for(cin >> T; T--;) {
		scanf("%d",&points);
		for(int i = 1; i <= points; ++i)
			point[i].Read(true);
		for(int i = points + 1; i <= (points << 1); ++i)
			point[i].Read(false);
		points <<= 1;
		sort(point + 1,point + points + 1);
		printf("%.3f\n",Solve(1,points));
	}
	return 0;
}

时间: 2024-10-10 05:41:08

POJ 3714 Raid 平面最近点对的相关文章

POJ 3714 Raid 最近对点题解

本题是一般最近对点求解,稍微增加点限定:有两个集合点,要求不同集合中的点的最近对. 那么就增加一个判断,如果是同一个集合中的点,那么就返回最大值,其他和一般的最近对点解法一样. 注意:本题数据有重合点,那么就要防止分类的时候溢出. Geeks上的最近对的程序是无法处理有重合点的情况的. #include <stdio.h> #include <stdlib.h> #include <float.h> #include <math.h> #include &l

POJ 3714 Raid(平面最近点对)

解题思路: 分治法求平面最近点对,点分成两部分,加个标记就好了. #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <vector> #include <queue> #include <algorithm> #include <iomanip>

poj 3714 Raid 分治法求平面最近点对

题意: 给平面上的n个点,求两点间的最短距离. 分析: 分治法,保存点用vector会tle... 代码: //poj 3714 //sep9 #include <iostream> #include <algorithm> #include <cmath> using namespace std; const double INF=1e50; struct P { double x,y; int type; }p[240000],b[240000]; bool cmp

【POJ 3714】 Raid

[题目链接] http://poj.org/problem?id=3714 [算法] 分治求平面最近点对 [代码] #include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio> #

poj 3714 最近点对

题意: 给出n个a类点,n个b类点,求a类点到b类点的最近距离. 限制: 1 <= n <= 1e5 0 <= x,y <= 1e9 思路: 点分治 /*poj 3714 题意: 给出n个a类点,n个b类点,求a类点到b类点的最近距离. 限制: 1 <= n <= 1e5 0 <= x,y <= 1e9 思路: 点分治 */ #include<iostream> #include<cstdio> #include<algorit

$Poj3714/AcWing\ Raid$ 分治/平面最近点对

$AcWing$ $Sol$ 平面最近点对板子题,注意要求的是两种不同的点之间的距离. $Code$ #include<bits/stdc++.h> #define il inline #define Rg register #define go(i,a,b) for(Rg int i=a;i<=b;++i) #define yes(i,a,b) for(Rg int i=a;i>=b;--i) #define mem(a,b) memset(a,b,sizeof(a)) #def

poj3714 Raid(分治求平面最近点对)

题目链接:https://vjudge.net/problem/POJ-3714 题意:给定两个点集,求最短距离. 思路:在平面最近点对基础上加了个条件,我么不访用f做标记,集合1的f为1,集合2的f为-1,那么求两个点的距离时,如果a.f*b.f=-1时计算距离,否则乘积为1的话返回inf.其它就和hdoj1007一样了. AC代码: #include<cstdio> #include<algorithm> #include<cmath> #include<cs

hdu1007 平面最近点对(暴力+双线程优化)

突发奇想,用双线程似乎可以优化一些暴力 比如说平面最近点对这个题目,把点复制成2份 一份按照x排序,一份按照y排序 然后双线程暴力处理,一份处理x,一份处理y 如果数据利用x递减来卡,那么由于双线程,它卡不住y 如果数据利用y递减来卡,那么卡不住x 这样暴力n^2就可以过了 #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algori

平面最近点对(分治nlogn)

平面最近点对,是指给出平面上的n个点,寻找点对间的最小距离 首先可以对按照x为第一关键字排序,然后每次按照x进行分治,左边求出一个最短距离d1,右边也求出一个最短距离d2,那么取d=min(d1, d2) 然后只需考虑横跨左右两侧的点,不妨枚举左侧的点pi 那么很显然的是如果pi距离中间的点超过了d,便可以直接舍去,只需考虑距离中间点小于d的点 这样一来就可以对每个pi画一个边长为2d的正方形,易证,矩形内最多存在8个点. 那么关键问题就是要快速找这8个点 朴素做法是对分治后的点进行快排,这样复