1. 程式人生 > >平面最近點對【kd樹初探】

平面最近點對【kd樹初探】

Description
    給出n個點,每個點座標為(xi,yi)。
    定義距離為D(A,B)=|xA-xB|+|yA-yB|
    求每個點到離它最近的點的距離


Input
    第一行為一個整數N
    接下來N行每行兩個整數xi,yi,表示第i個點的座標


Output
    輸出N行,每一行為第i個點的最近距離


Sample Input
4
0 0
0 1
1 0
1 1


Sample Output
1
1
1
1


Range
20% 0<N<1001

100% 0<N<200001,0<xi,yi<10,000,001

2D 3D KD-tree

k-d樹可以對k維空間進行劃分。

這裡我們只討論2維情況,多維的思想類似,實現起來也相差無幾。

每次選取一維(最好和之前的維度不同),找到它的中位數,以它為分割線把平面分割成2部分。

然後nth_element()一下,使對於當前維度左邊都是比mid值小的,右邊大的。

然後就遞迴

查詢的時候要注意,以最近點對為例,

假設由一條豎直的線  . |     目標點在左邊,先遞迴左邊找到最近距離S,目標點當前維度座標+S >分割線,說明右邊可能會有一個點使得答案更優。

另外一邊同理!

然後,就這道題而言,每個點離它最近的肯定是本身。就找離他最近的2個點,除去本身就是離它最近的點了!

在細節處理上有需要注意的地方,詳情參考程式碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=200000+20;
const int maxk=5;
int which,K;
int n;
int m;//平面最近m個點 
struct Point
{
	int x[maxk];
	bool operator<(const Point &p)const 
	{
		return x[which]<p.x[which];
	}
}x[maxn],aim,pr[maxn];
priority_queue<int>q;//儲存最近距離 
int ans[5];
int dis(const Point &a,const Point &b)
{
	int len=0;
	for(int i=0;i<K;i++)len+=abs(a.x[i]-b.x[i]);
	return len;
}
void build(int l,int r,int dep)
{
	if(l>r)return ;
	int mid=(l+r)>>1;
	which=dep%K;
	nth_element(x+l,x+mid,x+r+1);
	build(l,mid-1,dep+1);
	build(mid+1,r,dep+1);
}
void query(int l,int r,int dep)
{
	if(l>r)return ;
	int mid=(l+r)>>1,loc=dep%K;
	int len=dis(x[mid],aim);
	if(q.size()<m)q.push(len);
	else if(len<q.top()){q.pop();q.push(len);}
	if(l<r)
	{
		if(aim.x[loc]<x[mid].x[loc])
		{
			query(l,mid-1,dep+1);
			if(q.size()<m||aim.x[loc]+q.top()>x[mid].x[loc])query(mid+1,r,dep+1); 
		}
		else 
		{
			query(mid+1,r,dep+1);
			if(q.size()<m||aim.x[loc]-q.top()<x[mid].x[loc])query(l,mid-1,dep+1);
		}
	}
}
int main()
{
	freopen("find.in","r",stdin);
	freopen("find.out","w",stdout);
	//轉化為求平面最近2個點 
	K=2;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<K;j++)scanf("%d",&x[i].x[j]);
		pr[i]=x[i];
	}
	build(0,n-1,0);
	for(int t=0;t<n;t++)
	{
		for(int i=0;i<K;i++)aim.x[i]=pr[t].x[i];//x被重新排了序,所以造成了混亂,應該用之前的x
		//所以另外開個陣列儲存 
		m=2;
		while(!q.empty())q.pop();
		query(0,n-1,0);
		int cnt=0;
		while(!q.empty())
		{
			ans[cnt++]=q.top();
			q.pop();
		}
		printf("%d\n",ans[0]);
	}
	return 0;
}


相關推薦

平面最近kd初探

Description     給出n個點,每個點座標為(xi,yi)。     定義距離為D(A,B)=|xA-xB|+|yA-yB|     求每個點到離它最近的點的距離 Input     第一

[XSY 1145] 網絡戰爭 平面最近 最小割

val int tor else sum add name get tar   碼農題.   LEN 開到 1000 比較穩. 1 #include <cstdio> 2 #include <cstring> 3 #include &l

牛客練習賽11 B trie+拓撲判環 E 分治求平面最近

define ima 字典序 父親 name return 如果 int body 牛客練習賽11 B 假的字符串題意:給定n個字符串,互不相等,你可以任意指定字符之間的大小關系(即重定義字典序),求有多少個串可能成為字典序最小的串,並輸出它們。 tags:好題 對

題解平面最近(加強版)

double clas .org ace gpo bits scanf 簡單 name 洛谷P1429 很久以前就見過並想做的一道題…… 但大概是那個時候太蒻竟然一直不敢做呢,想想時間真的過得好快,從寫‘Hello World’到如今,其實也不過是短短的一個學期呀。 這道題

POJ3714Raid:平面最近

Description After successive failures in the battles against the Union, the Empire retreated to its last stronghold. Depending on its powerful defense sys

HDU1007Quoit Design(分治求平面最近

假設當前區間為[l,r] 中間點為mid 那麼最近點對 要麼在[1,l]中,要麼在[l+1,r]中,要麼兩邊各有一個 我們遞迴處理出左區間的 最近點對距離d1 右區間d2 取d=min(d1,d2) 然後有兩個剪枝來處理情況3 1.按x為關鍵字排個序,列舉[l,r]的點,假如一個點的x與中間點的x差值已經超過

BZOJ 4520 [Cqoi2016]K遠KD

font www tdi 進行 修改 距離 [1] ons blank 【題目鏈接】 http://www.lydsy.com/JudgeOnline/problem.php?id=4520 【題目大意】   求K遠點對距離 【題解】   修改估價

平面最近問題

ctype 但是 sof 算法 ans 之間 stream ant logs 平面最近點對問題正如其名,給定平面上的$n$個點,找出其中的一對點,使得這對點的距離在所有點對中最小。 首先顯而易見地我們可以得到這個問題的$O(n^2)$算法,枚舉所有點對即可。但是很顯然我

Luogu 1429 平面最近 | 平面分治

www poi alt spa fine 左右 str orm 修改 Luogu 1429 平面最近點對 題目描述 給定平面上n個點,找出其中的一對點的距離,使得在這n個點的所有點對中,該距離為所有點對中最小的 輸入輸出格式 輸入格式: 第一行:n;2≤n≤200000

HDU - 1007 平面最近

可能 eat use pla 合並 ase coord int largest Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at so

平面最近(加強版)

可能 一個 stream opera turn names main 中一 int 傳送門 ovo原來簡單版的非常的好做,只要肆意暴力枚舉即可。 不過這道題的數據範圍變成了200000,即使是洛谷神機也跑不過去的。 於是乎我們考慮分治法。 對於一個平面上的所有點,我們設其屬

POJ3714:求平面最近

mes == pre print pan 尋找 int nod cst 尋找兩個集合中的點的最近點對 1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #inc

「LuoguP1429」 平面最近(加強版)

urn dig tchar return article ron sdi nbsp git 題目描述 給定平面上n個點,找出其中的一對點的距離,使得在這n個點的所有點對中,該距離為所有點對中最小的 輸入輸出格式 輸入格式: 第一行:n;2≤n≤200

平面最近-分治

space name amp point syn cin std 很多 lin n2的暴力就算了。。 我們直接考慮怎樣優化: 我們考慮到可以先按x排序,然後分治,先分別求解兩個子問題。 假設我們已經求得了兩個子問題的答案。 那麽如果合並時,答案能夠更新,當且僅當兩個子區間中

Luogu P1429 平面最近(加強版)

P1429 平面最近點對(加強版) 題意 題目描述 給定平面上\(n\)個點,找出其中的一對點的距離,使得在這\(n\)個點的所有點對中,該距離為所有點對中最小的。 輸入輸出格式 輸入格式: 第一行:\(n\);\(2\leq n\leq 200000\) 接下來\(n\)行:每行兩個實數:\(

p1429 平面最近

題意:給平面n個點,求最近的兩個點的距離。 思路:運用分治思想,對於n個點,可以分成T(n/2)+T(n/2)的規模,分界線是x座標的中位數, 假設左邊點集合為s1, 右邊點集合為s2,那麼最小值存在於以下三種情況中。 1.s1中任意兩點距離的最小距離 2.s2中任意兩點距離的最

平面最近(分治)

一個 分治 ring 輸入輸出格式 class double amp include 最短 題目描述 給定平面上n個點,找出其中的一對點的距離,使得在這n個點的所有點對中,該距離為所有點對中最小的 輸入輸出格式 輸入格式: 第一行:n;2≤n≤20

分治法求平面最近

題意 Here 思考 之前考分治的時候有一道題,要用到 \(O(nlogn)\) 求平面最近點對,然而當時我不會……現在寫篇部落格回顧一下。 平面上 \(n\) 個點,讓我們求最近點對,最樸素的想法是列舉,複雜度 \(O(n^2)\) 這樣是顯然過不了 \(1e5\) 的資料的,同時我們也發現對於一

平面最近(nlogn)

#include <bits/stdc++.h> using namespace std; const int N = 2e5+1000; struct P{ double x, y; //此處修改int bool operator <(P B)cons

POJ平面最近

描述 二維平面上有N個點,求最近點對之間的距離。 輸入第一行一個整數T,表示有T組測試資料每組測試資料第一行一個整數N(2<=N<=1e5)表示平面有N個點接下來有N行,每行兩個整數X Y(-1e9<=X,Y <=1e9)表示點的座標輸出輸出最近點對的距離,精確到小數點後6位樣例輸