C語言分治(1)___平面最近點對問題
平面最近點對問題是指:在給出的同一個平面內的所有點的座標,然後找出這些點中最近的兩個點的距離.
方法1:窮舉
1)演算法描述:已知集合S中有n個點,一共可以組成n(n-1)/2對點對,蠻力法就是對這n(n-1)/2對點對逐對進行距離計算,通過迴圈求得點集中的最近點對
2)演算法時間複雜度:演算法一共要執行 n(n-1)/2次迴圈,因此演算法複雜度為O(n2)
程式碼實現:
利用兩個for迴圈可實現所有點的配對,每次配對算出距離然後更新最短距離.
for (i=0 ; i < n ;i ++){ for(j= i+1 ; j<n ;j ++){ 點i與點j的配對 } }
方法2:分治
1) 把它分成兩個或多個更小的問題;
2) 分別解決每個小問題;
3) 把各小問題的解答組合起來,即可得到原問題的解答。小問題通常與原問題相似,可以遞迴地使用分而治之策略來解決。
在這裡介紹一種時間複雜度為O(nlognlogn)的演算法。其實,這裡用到了分治的思想。將所給平面上n個點的集合S分成兩個子集S1和S2,每個子集中約有n/2個點。然後在每個子集中遞迴地求最接近的點對。在這裡,一個關鍵的問題是如何實現分治法中的合併步驟,即由S1和S2的最接近點對,如何求得原集合S中的最接近點對。如果這兩個點分別在S1和S2中,問題就變得複雜了。
為了使問題變得簡單,首先考慮一維的情形。此時,S中的n個點退化為x軸上的n個實數x1,x2,...,xn。最接近點對即為這n個實數中相差最小的兩個實數。顯然可以先將點排好序,然後線性掃描就可以了。但我們為了便於推廣到二維的情形,嘗試用分治法解決這個問題。
假設我們用m點將S分為S1和S2兩個集合,這樣一來,對於所有的p(S1中的點)和q(S2中的點),有p<q。
遞迴地在S1和S2上找出其最接近點對{p1,p2}和{q1,q2},並設
d = min{ |p1-p2| , |q1-q2| }
由此易知,S中最接近點對或者是{p1,p2},或者是{q1,q2},或者是某個{q3,p3},如下圖所示。
如果最接近點對是{q3,p3},即|p3-q3|<d,則p3和q3兩者與m的距離都不超過d,且在區間(m-d,d]和(d,m+d]各有且僅有一個點。這樣,就可以線上性時間內實現合併。
此時,一維情形下的最近點對時間複雜度為O(nlogn)。
在二維的情況下:
我們仿照一維的情況先把所有點按照x(橫座標)從左到右升序排列.
以X橫座標中間的點作為分界線.將平面的點分成左邊和右邊,以上圖為例,分為左邊5個右邊5個.
然後找到左邊的點中最近點對的距離d1,和右邊最近點對的距離d2。
令d=min{d1,d2}.那麼d是當前整個平面的最近點對的距離嗎?
答案不是!!
當前的d1,d2都是兩邊各自的點的最近距離,但是沒有考慮到兩邊的點相互配對的情況,即是點對一個在左邊區域,一個在右邊區域.
如果我們這個時候把兩邊相互配對的所有情況全部羅列出來那麼時間複雜度就變為第一種方法的O(n2).
這個時候我們便可以用上面找到的d來限制配對.即是明顯超過d的兩點不需要配對.如下:
那麼在範圍內的只有三個點,也就是說只有這個三個點相互配對的距離才可能比d小.那麼再按照方法一一樣在這些點中找到最短距離再跟d去比較.小的就是當前整個平面中所考慮的所有點中最近點對的距離。
然而在以上問題處理上,有一個問題尚未解決就是如何找到兩邊區域中的最近點對的距離d1,d2 ?
我們可以發現在處理上面這個問題的時候,和最開始處理所有平面的點最近點距離的問題類似,只是點的數目減半了.
那麼我們可以遞迴以上問題.直到劃分的區域中只有一個或者兩個點.這樣,該區域的最近點對距離就是無窮大或者該兩點的距離。這也是遞迴終止的條件。
樣例:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const double INF = 1e20;
const int N = 100005;
struct Point
{
double x;
double y;
}point[N];
int n;
int tmpt[N];
bool cmpxy(const Point& a, const Point& b)
{
if(a.x != b.x)
return a.x < b.x;
return a.y < b.y;
}
bool cmpy(const int& a, const int& b)
{
return point[a].y < point[b].y;
}
double min(double a, double b)
{
return a < b ? a : b;
}
double dis(int i, int j)
{
return sqrt((point[i].x-point[j].x)*(point[i].x-point[j].x)
+ (point[i].y-point[j].y)*(point[i].y-point[j].y));
}
double Closest_Pair(int left, int right)
{
double d = INF;
if(left==right)
return d;
if(left + 1 == right)
return dis(left, right);
int mid = (left+right)>>1;
double d1 = Closest_Pair(left,mid);
double d2 = Closest_Pair(mid+1,right);
d = min(d1,d2);
int i,j,k=0;
//分離出寬度為d的區間
for(i = left; i <= right; i++)
{
if(fabs(point[mid].x-point[i].x) <= d)
tmpt[k++] = i;
}
sort(tmpt,tmpt+k,cmpy);
//線性掃描
for(i = 0; i < k; i++)
{
for(j = i+1; j < k && point[tmpt[j]].y-point[tmpt[i]].y<d; j++)
{
double d3 = dis(tmpt[i],tmpt[j]);
if(d > d3)
d = d3;
}
}
return d;
}
int main()
{
while(true)
{
scanf("%d",&n);
if(n==0)
break;
for(int i = 0; i < n; i++)
scanf("%lf %lf",&point[i].x,&point[i].y);
sort(point,point+n,cmpxy);
printf("%.2lf\n",Closest_Pair(0,n-1)/2);
}
return 0;
}
相關推薦
C語言分治(1)___平面最近點對問題
平面最近點對問題是指:在給出的同一個平面內的所有點的座標,然後找出這些點中最近的兩個點的距離. 方法1:窮舉 1)演算法描述:已知集合S中有n個點,一共可以組成n(n-1)/2對點對,蠻力法就是對這n(n-1)/2對點對逐對進行距離計算,通過迴圈求得點集中的最近點對
分治_求解平面最近點對的O(nlg(n))演算法_演算法分析
本文主要講述經典的分治法求解平面最近點對的演算法, 為方便敘述, 先給出演算法的C+++實現示例, 然後給出演算法的正確性證明, 並分析其時間複雜度. //分治法求解平面最近點對 #include <iostream> #include &l
Luogu 1429 平面最近點對 | 平面分治
www poi alt spa fine 左右 str orm 修改 Luogu 1429 平面最近點對 題目描述 給定平面上n個點,找出其中的一對點的距離,使得在這n個點的所有點對中,該距離為所有點對中最小的 輸入輸出格式 輸入格式: 第一行:n;2≤n≤200000
牛客練習賽11 B trie樹+拓撲判環 E 分治求平面最近點對
define ima 字典序 父親 name return 如果 int body 牛客練習賽11 B 假的字符串題意:給定n個字符串,互不相等,你可以任意指定字符之間的大小關系(即重定義字典序),求有多少個串可能成為字典序最小的串,並輸出它們。 tags:好題 對
平面最近點對-分治
space name amp point syn cin std 很多 lin n2的暴力就算了。。 我們直接考慮怎樣優化: 我們考慮到可以先按x排序,然後分治,先分別求解兩個子問題。 假設我們已經求得了兩個子問題的答案。 那麽如果合並時,答案能夠更新,當且僅當兩個子區間中
平面最近點對(分治)
一個 分治 ring 輸入輸出格式 class double amp include 最短 題目描述 給定平面上n個點,找出其中的一對點的距離,使得在這n個點的所有點對中,該距離為所有點對中最小的 輸入輸出格式 輸入格式: 第一行:n;2≤n≤20
計算幾何 平面最近點對 nlogn分治演算法 求平面中距離最近的兩點
本文全文原創 轉載請註明出處 http://blog.csdn.net/lytning/article/details/25370169 平面最近點對,即平面中距離最近的兩點 分治演算法: int SOLVE(int left,int right)//求解點集中區間[lef
分治_平面最近點對_POJ3714_Raid
思路分析: AC程式碼如下, 就下面程式碼而言, 比較容易理解, 不予分析, 但是應該強調, 下面的程式碼不能算作典型的分治法求解平面最近點對的演算法, 為什麼這麼說 ? 因為經典的分治法
【HDU1007】Quoit Design(分治求平面最近點對)
假設當前區間為[l,r] 中間點為mid 那麼最近點對 要麼在[1,l]中,要麼在[l+1,r]中,要麼兩邊各有一個 我們遞迴處理出左區間的 最近點對距離d1 右區間d2 取d=min(d1,d2) 然後有兩個剪枝來處理情況3 1.按x為關鍵字排個序,列舉[l,r]的點,假如一個點的x與中間點的x差值已經超過
C語言BFS(1)___乳草的入侵
Farmer John一直努力讓他的草地充滿鮮美多汁的而又健康的牧草。可惜天不從人願,他在植物大戰人類中敗下陣來。邪惡的乳草已經在他的農場的西北部份佔領了一片立足之地。 草地像往常一樣,被分割成一個高度為Y(1 <= y <= 100), 寬度為X(1 <= x <= 100)的直角網
[XSY 1145] 網絡戰爭 平面最近點對 最小割樹
val int tor else sum add name get tar 碼農題. LEN 開到 1000 比較穩. 1 #include <cstdio> 2 #include <cstring> 3 #include &l
平面最近點對問題
ctype 但是 sof 算法 ans 之間 stream ant logs 平面最近點對問題正如其名,給定平面上的$n$個點,找出其中的一對點,使得這對點的距離在所有點對中最小。 首先顯而易見地我們可以得到這個問題的$O(n^2)$算法,枚舉所有點對即可。但是很顯然我
【題解】平面最近點對(加強版)
double clas .org ace gpo bits scanf 簡單 name 洛谷P1429 很久以前就見過並想做的一道題…… 但大概是那個時候太蒻竟然一直不敢做呢,想想時間真的過得好快,從寫‘Hello World’到如今,其實也不過是短短的一個學期呀。 這道題
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
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中任意兩點距離的最
分治法求平面最近點對
題意 Here 思考 之前考分治的時候有一道題,要用到 \(O(nlogn)\) 求平面最近點對,然而當時我不會……現在寫篇部落格回顧一下。 平面上 \(n\) 個點,讓我們求最近點對,最樸素的想法是列舉,複雜度 \(O(n^2)\) 這樣是顯然過不了 \(1e5\) 的資料的,同時我們也發現對於一