zoukankan      html  css  js  c++  java
  • 2017级算法模拟上机准备篇(计算几何 初阶_1)

    平面最近点对/最远点对

    Bamboo之吃我一拳(单纯的平面最近点对)

    零崎的战争(两个点集的平面最近点对)

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const double eps = 1e-6;
    const int maxn = 100010;
    const double INF = 1e20;
    struct point{
        double x,y;
        bool flag;
    };
    double dist(point a,point b){
        return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
    }
    point p[maxn] , temp[maxn];
    bool cmpxy(point a,point b){
        if(a.x != b.x) return a.x<b.x;
        else return a.y < b.y;
    }
    bool cmpy(point a,point b){
        return a.y < b.y;
    }
    double Closest_Pair(int left,int right){
        if(left == right) return INF;
        if(left+1 == right){
            if(p[left].flag != p[right].flag)
                return dist(p[left],p[right]);
            else return INF;
        }
        int mid=(left+right)/2;
        double d=min(Closest_Pair(left,mid),Closest_Pair(mid+1,right));
        int k=0;
        for(int i=left;i<=right;i++){
            if(fabs(p[mid].x - p[i].x) <=d )
                temp[k++]=p[i];
        }
        sort(temp,temp+k,cmpy);
        for(int i=0;i<k;i++)
            for(int j=i+1;j<k && temp[j].y-temp[j].y<d;j++)
                if(temp[i].flag != temp[j].flag)
                    d=min(d,dist(temp[i],temp[j]));
            return d;
    }
    int main(){
        int n,K;
        scanf("%d",&K);
        while(K--){
            scanf("%d",&n);
            for(int i=0;i<2*n;i++){
                scanf("%lf %lf",&p[i].x,&p[i].y);
                if(i<n) p[i].flag=true;
                else p[i].flag=false;
            }
            sort(p,p+n*2,cmpxy);
            printf("%.3lf
    ",Closest_Pair(0,2*n-1));
        }
        return 0;
    }

    平面最近点对实质上体现的还是分治的思想

    利用二分法将一个点集划分为两部分,那么平面最近点对只会存在于两个几何内部 或者在区间之间。

    利用递归计算出两个内部的最近距离之后,利用当前距离为标杆,控制判断区间之间的最近距离(剪枝后的遍历)最后返回答案即可。

    两个点集的最近点对,可以在原有代码的基础上增加区别集合与集合的falg 标示位,在计算距离之前,判断下这两个点是否在不同集合即可。

    寻找最远点对(单纯的平面最近点对)

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <string>
    using namespace std;
    struct Point
    {
     int x,y;
     Point(int _x = 0,int _y = 0)
     {
     x = _x; y = _y;
     }
     Point operator -(const Point &b)const
     {
     return Point(x - b.x, y - b.y);
     }
     int operator ^(const Point &b)const
     {
     return x*b.y - y*b.x;
     }
     int operator *(const Point &b)const
     {
     return x*b.x + y*b.y;
     }
     void input()
     {
     scanf("%d%d",&x,&y);
     }
    };
    //距离的平方
    int dist2(Point a,Point b)
    {
     return (a-b)*(a-b);
    }
    //******二维凸包,int***********
    const int MAXN = 50010;
    Point list[MAXN];
    int Stack[MAXN],top;
    bool _cmp(Point p1,Point p2)
    {
        int tmp = (p1-list[0])^(p2-list[0]);
         if(tmp > 0)return true;
         else if(tmp == 0 && dist2(p1,list[0]) <= dist2(p2,list[0]))
         return true;
         else return false;
        }
        void Graham(int n)
        {
         Point p0;
         int k = 0;
         p0 = list[0];
         for(int i = 1;i < n;i++)
         if(p0.y > list[i].y || (p0.y == list[i].y && p0.x > list[i].x))
         {
         p0 = list[i];
         k = i;
         }
         swap(list[k],list[0]);
         sort(list+1,list+n,_cmp);
         if(n == 1)
         {
         top = 1;
         Stack[0] = 0;
         return;
         }
         if(n == 2)
         {
         top = 2;
         Stack[0] = 0; Stack[1] = 1;
         return;
         }
         Stack[0] = 0; Stack[1] = 1;
         top = 2;
         for(int i = 2;i < n;i++)
         {
         while(top > 1 &&
        ((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <= 0)
         top--;
         Stack[top++] = i;
         }
        }
        //旋转卡壳,求两点间距离平方的最大值
        int rotating_calipers(Point p[],int n)
        {
         int ans = 0;
         Point v;
         int cur = 1;
         for(int i = 0;i < n;i++)
         {
         v = p[i]-p[(i+1)%n];
         while((v^(p[(cur+1)%n]-p[cur])) < 0)
         cur = (cur+1)%n;
         ans = max(ans,max(dist2(p[i],p[cur]),dist2(p[(i+1)%n],p[(cur+1)%n])));
         }
         return ans;
        }
        Point p[MAXN];
        int main()
        {
             int n;
             while(scanf("%d",&n) == 1)
             {
             for(int i = 0;i < n;i++)list[i].input();
             Graham(n);
             for(int i = 0;i < top;i++)p[i] = list[Stack[i]];
             printf("%d
    ",rotating_calipers(p,top));
             }
             return 0;
        }

    kuangbin 大大的板子(侵删)

    这道题首先可以确认的是最远点对一定在凸包上。

    求出凸包以后,作两点的平行线,当一点到平行线的方向发生改变时达到可能的最大值(旋转卡壳)。然后旋转到每个点都考虑完毕就可以了。

  • 相关阅读:
    javascript form表单常用的正则表达式
    jquery判断邮箱对错
    利用js实现placeholder占位符,甩开ie不兼容
    jquery常用的选择器
    html+css底部自动固定底部
    css form表单样式清除
    js alert(“”)弹框 自定义样式
    Vue.js 源码分析(二十三) 指令篇 v-show指令详解
    Vue.js 源码分析(二十一) 指令篇 v-pre指令详解
    Vue.js 源码分析(二十) 指令篇 v-once指令详解
  • 原文地址:https://www.cnblogs.com/visper/p/10123805.html
Copyright © 2011-2022 走看看