zoukankan      html  css  js  c++  java
  • bzoj 2458: [BeiJing2011]最小三角形 题解

    【前言】话说好久没有写题解了。到暑假了反而忙。o(╯□╰)o

    【原题】

    2458: [BeiJing2011]最小三角形

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 574  Solved: 177
    [Submit][Status]

    Description

    Xaviera如今遇到了一个有趣的问题。
    平面上有N个点。Xaviera想找出周长最小的三角形。
    因为点许多。分布也很乱,所以Xaviera想请你来解决问题。
    为了减小问题的难度,这里的三角形也包含共线的三点。

    Input

    第一行包括一个整数N表示点的个数。
    接下来N行每行有两个整数,表示这个点的坐标。

    Output

    输出仅仅有一行。包括一个6位小数,为周长最短的三角形的周长(四舍五入)。

    Sample Input

    4
    1 1
    2 3
    3 3
    3 4

    Sample Output

    3.414214


    HINT

    100%的数据中N≤200000。

    Source


    【分析】今天新学了解决这类问题的方法——分治。

    没错,就是分治。

    先讲一下n是10^5级别的平面近期点对吧(CF 245 DIV 2 D)。非常easy懂。

    具体的原理能够參考这个博客。讲的非常具体。

    (非常多时候仅仅要感性认识原理就可以)以下讲一下具体做法。

    ①对于平面上的点。按x坐标排序(这是永久排序)。

    ②每次递归(l。r)。函数的返回值是第l个到第r个之间的全部点的近期点对。

    ③假设l=r。那么返回无穷大;假设l+1=r。就直接返回两个点的距离。

    ④每次先递归(l。mid)和(mid+1,r)。显然,这两个会有两个返回值。最好还是设为d1和d2。

    首先我们设D=MIN(d1,d2)。即当前的最优值临时是D。

    ⑤显然,另一种情况。左边那块的某个点和右边那块的某个点产生关系。那么,我们能够从mid这个位置向左跑到mid-D,向右跑到mid+D,然后把这一段中的点都拎出来——由于仅仅有这两段中的点才有可能产生小于D的贡献。

    ⑥这时候我们要意识到潜在复杂度的保证(实际原理也不难懂呵)。

    首先,假设直接枚举两两点要N^2。我们先把拎出来的点按y排序。

    (NlogN)然后看似也是N^2的枚举,仅仅是加了一个优化(从底下開始枚举i。假设Y[J]-Y[I]>D就直接break)——这样可证明差点儿是线性。

    总复杂度N*logN*logN。

    再讲一下本题。也是几乎相同道理。

    由于是三角形,我们把一些细节改一下就可以。

    【代码】

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define N 200005
    #define INF 210000000000.0
    using namespace std;
    struct arr{int x,y;}a[N],num[N];int n,i,Test;
    inline bool cmpx(const arr &a,const arr &b){return a.x<b.x;}
    inline bool cmpy(const arr &a,const arr &b){return a.y<b.y;}
    inline double dis(const arr &a,const arr &b){return sqrt((a.x-b.x)*1.*(a.x-b.x)+(a.y-b.y)*1.*(a.y-b.y));}
    inline double work(int l,int r)
    {
      if (l==r) return INF;
      if (l+1==r) return INF;
      if (l+2==r) return dis(a[l],a[l+1])+dis(a[l+1],a[r])+dis(a[l],a[r]);
      int mid=(l+r)>>1;
      double d1=work(l,mid),d2=work(mid+1,r);
      double D=min(d1,d2),ans=D,DD=D/2.0;int cnt=0;
      for (int i=l;i<=r;i++)
        if (fabs(a[mid].x-a[i].x)<=DD) num[++cnt]=a[i];
      sort(num+1,num+cnt+1,cmpy);
      for (int i=1;i<cnt-1;i++)
        for (int j=i+1;j<cnt;j++)
        {
          if (num[j].y-num[i].y>DD) break;
          for (int k=j+1;k<=cnt;k++)
          {
            if (num[k].y-num[i].y>DD) break;
            double temp=dis(num[i],num[j])+dis(num[i],num[k])+dis(num[j],num[k]);
            if (temp<ans) ans=temp;
          }
        }
      return ans;
    }
    int main()
    {
      read(n);//读入优化就不贴了。

    for (i=1;i<=n;i++) read(a[i].x),read(a[i].y); sort(a+1,a+n+1,cmpx); printf("%.6lf",work(1,n)); return 0; }

  • 相关阅读:
    CDQ
    MySQL中的类Decode用法
    HTMLTestRunner生成空白resault.html
    参数化时按行读取txt文件,如何去掉换行符" "
    打开本地html的一些设置
    python中文乱码例子
    Python异常处理实例
    Python根据上下限生成不重复随机数1
    Linux自定义命令
    Python IDLE 清屏工具
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/6790965.html
Copyright © 2011-2022 走看看