一,平面最近點對
問題:在給n個平面上的點,讓你找到最近的一對點。
暴力n*n做法肯定超時。
我們考慮分治。
1-n這個區間,我們可以先找到a=(1-mid)和b=(mid+1,n)這個區間的最小點對。並一直遞迴下去。
現在主要的問題,在於如何對這兩個區間進行合併操作。
因為,也許最近點對是a區間乙個點b區間乙個點。
我們可以繼續考慮
合併這兩個區間,我們有必要把這兩個區間所有的點都拿來比較一下嗎?
肯定是沒有必要的。
假如當前所求的最小距離為minx,同時我們可以把a[mid]作為乙個旗標。
a區間和b區間的點離旗標之間的距離如果大於minx。那我肯定就不用考慮了。
所以我們合併的時候要考慮的x範圍是[a[mid] - minx,a[mid] + minx]。超過這個範圍的x,距離一定會比minx大。
可是這樣還不夠,萬一所考慮的區間很多點,那複雜度還是降不下來。
我們用考慮x的想法繼續去考慮y。
對於乙個點a的y來說,與點a的最近點b的y,一定不會離a的y差minx距離。
所以我們用這種方法可以把所考慮到的點降低到只有7個點。
為什麼是7個點呢?
可看下面這篇證明:
參考部落格: 大佬的**很好懂了。
例題一:
這題是裸題,可以做模板了。(逃,巨弱還是錯了n次,痛
#include"stdio.h
"#include
"string.h
"#include
"vector
"#include
"math.h
"#include
"algorithm
"using
namespace
std;
typedef
struct
nodenode;
intn;
node node[
200100
];node tran[
200100
];double minx =1e20;
bool same(double a, double b)
intcmpx(node a,node b)
intcmpy(node a,node b)
void
dist_minx(node a,node b)
void merge_node(int l,int mid,intr)
else
}while(i <= mid) tran[++ t] = node[i ++];
while(j <= r) tran[++ t] = node[j ++];
for(int i = l; i <= r; i ++)
node[i] = tran[i - l + 1];}
void blocking(int l,int
r) }
sort(node + l,node + r + 1
,cmpy);
return
; }
int mid = (l + r) >> 1
;
double midx =node[mid].x;
blocking(l,mid); blocking(mid + 1
,r);
merge_node(l,mid,r);
vector
q;
for(int i = l; i <= r; i ++)
q.push_back(node[i]);
}q.clear();
return;}
intmain()
sort(node + 1,node + n + 1
,cmpx);
blocking(
1,n);
printf(
"%0.4lf\n
",minx);
}
例題二:
題意是要我們找到一對點:類似於最近點對的sqrt((xi+xj)^2 +(yi+yj)^2)使其值最小的點對。
觀察可得,這個式子是不是跟兩點間的距離就只差了乙個符號。
那我們可以把式子轉化為:sqrt((xi-(-xj))^2 +(yi-(-yj))^2)
在根據題意,乙個點可以自由轉化為帶負數的形式。就可做了。
吐了,cmpx寫錯導致浪費了3個小時。
注意:你不能直接在求路徑的時候加負數。這會導致你的y排序不滿足的問題。
所以,我們應該在最後的時候在把k轉換過來。
#include"stdio.h"#include"string.h"
#include"vector"
#include#include"math.h"
#include"algorithm"
using namespace std;
typedef long long ll;
typedef struct nodenode;
int n;
node node[800100];
node tran[800100];
ll minx = long_long_max;
int v1,v2,s1,s2;
int cmpx(node a,node b) return ;
}void merge_node(int l,int mid,int r)
else
}while(i <= mid) tran[++ t] = node[i ++];
while(j <= r) tran[++ t] = node[j ++];
for(int i = l; i <= r; i ++)
node[i] = tran[i - l + 1];
}void blocking(int l,int r)
}sort(node + l,node + r + 1,cmpy);
return ;
}int mid = (l + r) >> 1;
ll midx = node[mid].x;
blocking(l,mid); blocking(mid + 1,r);
merge_node(l,mid,r);
vectorq;
for(int i = l; i <= r; i ++)
q.push_back(node[i]);
}q.clear();
return ;
}int main()
n = n * 4;
sort(node + 1,node + n + 1,cmpx);
blocking(1,n);
printf("%d %d %d %d\n",v1,s1,v2,5 - s2);
}
平面最近點對
求點集中的最近點對有以下兩種方法 設p1 x1,y1 p2 x2,y2 pn xn,yn 是平面上n個點構成的集合s,設計演算法找出集合s中距離最近的點對。1 蠻力法 適用於點的數目比較小的情況下 1 演算法描述 已知集合s中有n個點,一共可以組成n n 1 2對點對,蠻力法就是對這n n 1 2 ...
平面最近點對
求點集中的最近點對有以下兩種方法 設p1 x1,y1 p2 x2,y2 pn xn,yn 是平面上n個點構成的集合s,設計演算法找出集合s中距離最近的點對。1 蠻力法 適用於點的數目比較小的情況下 1 演算法描述 已知集合s中有n個點,一共可以組成n n 1 2對點對,蠻力法就是對這n n 1 2對...
平面最近點對
求點集中的最近點對有以下兩種方法 設p1 x1,y1 p2 x2,y2 pn xn,yn 是平面上n個點構成的集合s,設計演算法找出集合s中距離最近的點對。1 蠻力法 適用於點的數目比較小的情況下 1 演算法描述 已知集合s中有n個點,一共可以組成n n 1 2對點對,蠻力法就是對這n n 1 2對...