• kd树解平面最近点对


    早上起来头有点疼,突然就想到能不能用kd树解平面最近点对问题,就找了道题试了一下,结果可以,虽然效率不高,但还是AC了~

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1007

    题目要求平面上最近点对间距离的一半。

    思路如下:先建立一棵树,所有点插入树中,之后为每个点查询其最近点,枚举找到最小值。注意查询的时候不要让点自己跟自己比。个人感觉,这种写法也可以达到O(nlogn)的复杂度。建树分区间的时候,按x,y中跨度大的一个来分,应该就接近O(nlogn)了,不过我太懒了,那种方法之后再试,现在先x,y轮流着来了。

    kd树代码如下:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <queue>
     5 #include <cstdio>
     6 #include <cmath>
     7 #define MAX (101000)
     8 #define pow(x) ((x)*(x))
     9 
    10 using namespace std;
    11 
    12 int n, idx;
    13 
    14 struct Point{
    15     double x[2];
    16     bool operator < (const Point &u) const{
    17         return x[idx] < u.x[idx];
    18     }
    19 }po[MAX];
    20 
    21 struct Tree {
    22     Point p[MAX<<2];
    23     int son[MAX<<2];
    24     bool f[MAX<<2];
    25     int ps[MAX<<2];
    26     void build ( int l , int r , int u = 1, int dep = 0)
    27     {
    28         if(l > r) return;
    29         son[u] = r-l;
    30         son[u<<1] = son[u<<1|1] = -1;
    31         idx = dep%2;
    32         int mid = (l+r)>>1;
    33         nth_element(po+l, po+mid, po+r+1);
    34         p[u] = po[mid], ps[u] = mid;
    35         build ( l , mid-1 , u<<1 , dep+1 );
    36         build ( mid+1 , r , u<<1|1 , dep+1 );
    37     }
    38 
    39     double query(Point a, int id, int u = 1, int dep = 0){
    40         if(son[u] == -1) return 1000000000.0;
    41 
    42         double dis = pow(p[u].x[0]-a.x[0]) + pow(p[u].x[1]-a.x[1]);
    43         if(ps[u] == id) dis = 1000000000.0;
    44         int dim = dep%2, fg = 0;
    45         int x = u<<1, y = u<<1|1;
    46         if(a.x[dim] >= p[u].x[dim]) swap(x, y);
    47         double tm1 = 1000000000.0, tm2 = 1000000000.0;
    48         if(~son[x])tm1 = query(a, id, x, dep+1);
    49         if(pow(a.x[dim] - p[u].x[dim]) < tm1) fg = 1;
    50         if(~son[y] && fg) tm2 = query(a, id, y, dep+1);
    51         if(dis > tm1) dis = tm1;
    52         if(dis > tm2) dis = tm2;
    53         return dis;
    54     }
    55 }kd;
    56 
    57 
    58 int main(){
    59     while(~scanf("%d", &n), n){
    60         for(int i = 0; i < n; i++)
    61                 scanf("%lf %lf", &po[i].x[0], &po[i].x[1]);
    62         memset(kd.f, 0, sizeof(kd.f));
    63         memset(kd.ps, -1, sizeof(kd.ps));
    64         kd.build(0, n-1);
    65         double ans = 1000000000.0;
    66         for(int i = 0; i < n; i++){
    67             double tm = kd.query(po[i], i);
    68             if(tm < ans) ans = tm;
    69         }
    70         printf("%.2lf
    ", sqrt(ans)/2);
    71     }
    72     return 0;
    73 }
  • 相关阅读:
    多个数字和数字字符串混合运算规则
    关于js对象引用的小例子
    实现函数 isInteger(x) 来判断 x 是否是整数
    写一个少于 80 字符的函数,判断一个字符串是不是回文字符串
    关于数组排序
    事件委托(事件代理)的原理以及优缺点是什么?
    将url的查询参数解析成字典对象
    js dom操作获取节点的一些方法
    js中arguments的应用
    深度克隆---js对象引用
  • 原文地址:https://www.cnblogs.com/beisong/p/4427654.html
Copyright © 2020-2023  润新知