kd-Tree 【专题@AbandonZHANG】

半腔热情 提交于 2020-04-02 03:34:58
刚开始学习,介绍先搁着~等理解透彻了再来写~~~   我是学习的mzry1992(UESTC_Izayoi ~)------http://www.mzry1992.com/blog/miao/kd%E6%A0%91.html 先去看mzry1992大牛博客里的讲解吧。。。   再附两篇论文:(看英文看得好爽。。。~@.@) 《An intoductory tutorial on kd-trees》  ★(里面就介绍了kd-tree和nearest neighbour algorithm(最近邻算法)、Q nearest neighbour(Q近邻) 《Range Searching Using Kd-Tree.》    kd-tree入门题:     HDOJ 2966 In case of failure (最近邻,模板~)   查找平面点最近点的距离(此题中是距离的平方)
/*
    HDOJ 2966
    KD-Tree模板
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MID(x, y) ( (x + y)>>1 )

using namespace std;
typedef long long LL;

//KD-Tree模板
const int N=100005;
LL res;
struct Point
{
    int x, y;        //点是二维的,此时是2D-Tree
};

LL dist2(const Point &a, const Point &b)            //距离的平方
{
    return LL(a.x - b.x) * LL(a.x - b.x) + LL(a.y - b.y) * LL(a.y - b.y);
}

bool cmpX(const Point &a, const Point &b)
{
    return a.x  r)    return;
        int mid=MID(l, r);
        int minX, minY, maxX, maxY;
        minX = min_element(p + l, p + r + 1, cmpX)->x;
        minY = min_element(p + l, p + r + 1, cmpY)->y;
        maxX = max_element(p + l, p + r + 1, cmpX)->x;
        maxY = max_element(p + l, p + r + 1, cmpY)->y;
        Div[mid] = (maxX - minX >= maxY - minY);
        nth_element(p + l, p + mid, p + r + 1, Div[mid] ? cmpX : cmpY);
        build(l, mid - 1);
        build(mid+1, r);
    }

    void find(int l, int r, Point a)                //查找最近点的平方距离
    {
        if (l > r)    return;
        int mid = MID(l, r);
        LL dist = dist2(a, p[mid]);
        if (dist > 0)   //如果有重点不能这么判断
            res = min(res, dist);
        LL d = Div[mid] ? (a.x - p[mid].x) : (a.y - p[mid].y);
        int l1, l2, r1, r2;
        l1 = l , l2 = mid + 1;
        r1 = mid - 1, r2 = r;
        if (d > 0)
            swap(l1, l2), swap(r1, r2);
        find(l1, r1, a);
        if (d * d 

  HDOJ 4347 The Closest M Points (Q近邻)

  与上题不同的是,一是k维(这个好处理~),二是求最近的m个点而不单是最近点了。这个也好处理~递归查找时处理的时候采取如下策略:如果当前找到的点小于k个,那么两个区间都要处理。。否则根据当前找到的第k个点决定是否去另外一个区间,如果目标点到分界线的距离大于等于已经找到的第k远的点,那么就不用查找另一个分界了。。。更新答案可以用一个大小为k的堆去维护(一个最大堆,一旦超过k个点就把最大的扔掉)。。。

#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #define MID(x,y) ( (x + y)>>1 )
 
 using namespace std;
 typedef long long LL;
 
 //KD-Tree模板
 const int N=50005;
 
 struct Point
 {
     int x[5];
     LL dis;
     Point()
     {
         for (int i = 0; i x[i];
             maxx[i] = max_element(p + l, p + r + 1, cmpX)->x[i];
             ms[maxx[i] - minx[i]] = i;
         }
         map ::iterator pm = ms.end();
         pm--;
         return pm->second;
     }
 
     void build(int l, int r)            //记得先把p备份一下。
     {
         if (l > r)    return;
         int mid = MID(l,r);
         Div[mid] = getDiv(l,r);
         ddiv = Div[mid];
         nth_element(p + l, p + mid, p + r + 1, cmpX);
         build(l, mid - 1);
         build(mid + 1, r);
     }
 
     void findk(int l, int r, Point a)                //k(m)近邻,查找k近点的平方距离
     {
         if (l > r)    return;
         int mid = MID(l,r);
         LL dist = dist2(a, p[mid], k);
         if (dist >= 0)
         {
             p[mid].dis = dist;
             res.push(p[mid]);
             while ((int)res.size() > m)
                 res.pop();
         }
         LL d = a.x[Div[mid]] - p[mid].x[Div[mid]];
         int l1, l2, r1, r2;
         l1 = l , l2 = mid + 1;
         r1 = mid - 1, r2 = r;
         if (d > 0)
             swap(l1, l2), swap(r1, r2);
         findk(l1, r1, a);
         if ((int)res.size() = 0; i--)
             {
                 for (int j = 0; j 

 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!