zoukankan      html  css  js  c++  java
  • 洛谷1429 平面最近点对(KDTree)

    qwq(明明可以直接分治过掉的)

    但是还是当作联系了

    首先,对于这种点的题,很显然的套路,我们要维护一个子树(mx[i],mn[i])分别表示每个维度的最大值和最小值
    (这里有一个要注意的东西!就是我们(up)的时候,要判断一下当前是否还有左/右儿子)

    bool operator< (KD a,KD b)
    {
        return a.d[ymh]<b.d[ymh];
    }
    void up(int root)
    {
       for (int i=0;i<=1;i++)
       {
          if (t[root].l)
          {
            t[root].mn[i]=min(t[root].mn[i],t[t[root].l].mn[i]);
            t[root].mx[i]=max(t[root].mx[i],t[t[root].l].mx[i]);
          }
          if (t[root].r)
          {
            t[root].mn[i]=min(t[root].mn[i],t[t[root].r].mn[i]);
            t[root].mx[i]=max(t[root].mx[i],t[t[root].r].mx[i]);
          }
       }
    }
    void build(int &x,int l,int r,int dd)
    {
        ymh = dd;
        int mid = l+r >> 1;
        x = mid;
        nth_element(t+l,t+x,t+r+1);
        for (int i=0;i<=1;i++) t[x].mn[i]=t[x].mx[i]=t[x].d[i];
        if (l<x) build(t[x].l,l,mid-1,dd^1);
        if (x<r) build(t[x].r,mid+1,r,dd^1);
        up(x);
    }
    
    
    

    其实这个题最重要的是估价函数该怎么写。

    首先我们很容易发现,因为我们要求的是这个子树理论上到那个点的最短距离,所以我们需要这么考虑,如果当前点的坐标在(mn到mx)之间的话,那么理论上的最短距离就是0,否则就是当前这一维度距离(mn和mx)较近的距离

    double calc(KD a,KD b)
    {
        double tmp=0;
        for (int i=0;i<=1;i++)
        {
            if (b.d[i]<a.mn[i]) tmp=tmp+(a.mn[i]-b.d[i])*(a.mn[i]-b.d[i]);
            else if (b.d[i]>a.mx[i]) tmp=tmp+(a.mx[i]-b.d[i])*(a.mx[i]-b.d[i]);
        }
        return sqrt(tmp);
    }
    

    其实剩下的就是和普通的kdtree差不多了

    直接上就好了

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define mk makr_pair
    #define ll long long
    using namespace std;
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    const int maxn = 2e5+1e2;
    struct KD{
        double mx[4],mn[4],d[4];
        int l,r;
    };
    KD t[maxn],now;
    int n,m,root;
    int ymh;
    double ans;
    double tmp;
    int ii =0;
    bool operator< (KD a,KD b)
    {
        return a.d[ymh]<b.d[ymh];
    }
    void up(int root)
    {
       for (int i=0;i<=1;i++)
       {
          if (t[root].l)
          {
            t[root].mn[i]=min(t[root].mn[i],t[t[root].l].mn[i]);
            t[root].mx[i]=max(t[root].mx[i],t[t[root].l].mx[i]);
          }
          if (t[root].r)
          {
            t[root].mn[i]=min(t[root].mn[i],t[t[root].r].mn[i]);
            t[root].mx[i]=max(t[root].mx[i],t[t[root].r].mx[i]);
          }
       }
    }
    void build(int &x,int l,int r,int dd)
    {
        ymh = dd;
        int mid = l+r >> 1;
        x = mid;
        nth_element(t+l,t+x,t+r+1);
        for (int i=0;i<=1;i++) t[x].mn[i]=t[x].mx[i]=t[x].d[i];
        if (l<x) build(t[x].l,l,mid-1,dd^1);
        if (x<r) build(t[x].r,mid+1,r,dd^1);
        up(x);
    }
    double getdis(int a,KD b)
    {
        if (!a) return 0;
        double tmp=0;
        for (int i=0;i<=1;i++)
        {
            tmp=tmp+(t[a].d[i]-b.d[i])*(t[a].d[i]-b.d[i]);
        }
        return sqrt(tmp);
    }
    double calc(KD a,KD b)
    {
        double tmp=0;
        for (int i=0;i<=1;i++)
        {
            if (b.d[i]<a.mn[i]) tmp=tmp+(a.mn[i]-b.d[i])*(a.mn[i]-b.d[i]);
            else if (b.d[i]>a.mx[i]) tmp=tmp+(a.mx[i]-b.d[i])*(a.mx[i]-b.d[i]);
        }
        return sqrt(tmp);
    }
    void query(int x)
    { 
        if (!x) return;
        double d1 = calc(t[t[x].l],now);
        double d2 = calc(t[t[x].r],now);
        double d = getdis(x,now);
        if (d<tmp && d!=0) tmp = d;
        if (d==0) ii++;
        if (d1<d2)
        {
            if (d1<tmp) query(t[x].l);
            if (d2<tmp) query(t[x].r);
        }
        else
        {
            if (d2<tmp) query(t[x].r);
            if (d1<tmp) query(t[x].l);
        }
    }
    int main()
    {
      n=read();
      for (int i=1;i<=n;i++)
        for (int j=0;j<=1;j++) t[i].d[j]=read();
      build(root,1,n,0);
      tmp = 1e18;
      for (int i=1;i<=n;i++)
      {
       ii=0;
       now = t[i];
       query(root);
       if (ii>1) tmp=0;
      }
      printf("%.4lf",tmp);
      return 0;
    }
    
  • 相关阅读:
    中国大学排名爬虫
    基于bs4库的HTML内容查找方法和HTML格式化和编码
    自动化提取51啦数据的信息
    简单目录扫描工具
    一个简单音乐播放器
    【原创】C++中对象的序列化
    [android]android开发中的运行错误之:adb.exe
    [转载]十大编程算法助程序员走上高手之路
    [原创]二叉树相关笔试题代码
    [原创]VS2010中创建动态链接库及其调用
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10161961.html
Copyright © 2011-2022 走看看