zoukankan      html  css  js  c++  java
  • 凸包

    转自https://www.cnblogs.com/wuwangchuxin0924/p/6223152.html

    了解凸包及Graham扫描法

           问题描述:二位平面内,给定n个散乱的点,求一个最小凸多边形(凸包),使得n个点都不在凸多边形外。

           问题的解决用到Graham算法:

    算法步骤:

      1.取y坐标最小的一点,作为p0,显然p0一定在凸包上。

     

      2.将p0作为坐标系原点,其他点按极角从小到大排序,从p1开始编号。

     

      3.从小到大遍历所有点:显然[p0, p1] 在凸包中

     

      4.连接p1, p2的时候需要判断:p0->p1 叉乘 p1->p2 是否大于0:

        > 0 p1->p2 在 p0->p1 夹角小于π,物理意义:p1->p2 在 p0->p1的左边,满足凸多边形定义。

        = 0 p1->p2 与 p0->p1 共线,同向满足,相反不满足。

        < 0 p1->p2 在 p0->p1 夹角大于π,不满足。

     

      5.连接p2, p3 向量p2->p3在p1->p2左边,满足定义,当连接p3, p4的时候,发现不满足定义了,此时要放弃p3, 从p2开始回溯,找到第一个满足要求的点。

     

      6.以此类推,知道回到p0点。

     

    Graham scan 正确性:

           令散点的数量为k,散点(p0 ~ pk – 1)已经按照极角排序。

           当k=3时,显然,p0->p1时凸包的一条边,且p2 极角小于p1, 那么p1->p2在p0->p1的左侧,所以p1->p2保留。

           当k=n时,假设此时(p0 ~ pn – 1) 都按照Graham scan找出“最完美的凸包”

           当k=n+1时,如果pn – 1 -> pn 在 pn – 2 > pn – 1左边,如下图,如果舍弃pn,直接连接pn – 1 -> p0, 那么pn在多边形外,不满足要求。

          

                  证毕。

    代码实现:

    /****************************凸包模板*******************************/
    
    const double eps = 1e-8;
    
    int sgn(double x) {
      if (fabs(x) < eps)
        return 0;
    
      if (x < 0)
        return -1;
      else
        return 1;
    }
    
    struct Point {
      double x, y;
      Point() {}
      Point(double _x, double _y) {
        x = _x;
        y = _y;
      }
    
      Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }
      //叉积
      double operator^(const Point &b) const { return x * b.y - y * b.x; }
      //点积
      double operator*(const Point &b) const { return x * b.x + y * b.y; }
      void input() {
        scanf("%lf%lf", &x, &y);
      }
    };
    
    struct Line {
      Point s, e;
      Line() {}
      Line(Point _s, Point _e) {
        s = _s;
        e = _e;
      }
    };
    
    //*两点间距离
    double dist(Point a, Point b) { return sqrt((a - b) * (a - b)); }
    
    /*
     * 求凸包,Graham算法
     * 点的编号0~n-1
     * 返回凸包结果Stack[0~top-1]为凸包的编号
     */
    
    const int MAXN = 1010;
    Point List[MAXN];
    int Stack[MAXN];  //用来存放凸包的点
    int top;  //表示凸包中点的个数
    
    //相对于List[0]的极角排序
    
    bool _cmp(Point p1, Point p2) {
      double tmp = (p1 - List[0]) ^(p2 - List[0]);
      if (sgn(tmp) > 0)
        return true;
      else if (sgn(tmp) == 0 && sgn(dist(p1, List[0]) - dist(p2, List[0])) <= 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 &&
            sgn((List[Stack[top - 1]] - List[Stack[top - 2]]) ^ (List[i] - List[Stack[top - 2]])) <= 0)
          top--;
        Stack[top++] = i;
      }
    }
    
    /****************************凸包模板*******************************/
    View Code
  • 相关阅读:
    利用条件信号量设计读写锁
    高效编程之互斥锁和自旋锁的一些知识
    高效编程之指针跳转的影响
    高效编程之cache命中对于程序性能的影响
    SQL Server中使用自定义指定顺序排序
    Vue使用,异步获取日期时间后格式成"/Date(1333245600000+0800)/" 转换成正常格式
    技术胖-胜洪宇关注web前端技术
    百度editor编辑器添加新字体
    mvc4中的 webapi 的使用方式
    js特效不错的网站
  • 原文地址:https://www.cnblogs.com/Lemon1234/p/11635207.html
Copyright © 2011-2022 走看看