Выпуклая оболочка: различия между версиями

Материал из Олимпиадное программирование в УлГТУ
Перейти к навигации Перейти к поиску
Нет описания правки
Строка 4: Строка 4:
* Рассматриваем остальные точки в порядке сортировки по углу. Пока две последние точки оболочки вместе с новой точкой лежат на одной прямой или дают поворот по часовой стрелке (косое произведение неотрицательно), выкидываем последнюю точку из оболочки. Добавляем следующую точку в оболочку.
* Рассматриваем остальные точки в порядке сортировки по углу. Пока две последние точки оболочки вместе с новой точкой лежат на одной прямой или дают поворот по часовой стрелке (косое произведение неотрицательно), выкидываем последнюю точку из оболочки. Добавляем следующую точку в оболочку.


{|
  struct Point {
| width="50%"  | 
     double x, y;
 
  struct P {  
     Point() {}
     double x, y;  
     P(double X, double Y) : x(X), y(Y) {}  
    Point(const Point &a, const Point &b) : x(b.x - a.x), y(b.y - a.y) {}
    bool operator < (const Point &that) const {
        return y < that.y || y == that.y && x < that.x;
    }
     double length() const {
     double length() const {
         return sqrt(y * y + x * x);
         return hypot(x, y);
     }  
     }
     double cross(const P &p) const {
         return x * p.y - y * p.x;
     double crossProduct(const Point &that) const {
     }  
         return x * that.y - y * that.x;
     }
  };
  };
   
   
  bool compareByCoords(const P &a, const P &b) {
Point o;
     return a.y &lt; b.y || (a.y == b.y && a.x &lt; b.x);
  bool compareByAngle(const Point &a, const Point &b) {
     Point oa(o, a), ob(o, b);
    return oa.crossProduct(ob) > 0 || oa.crossProduct(ob) == 0 && oa.length() < ob.length();
  }
  }
   
   
  P o(0, 0);
  vector<Point> convexHull(vector<Point> &points) {
bool compareByAngle(const P &a, const P &b) {
     sort(points.begin(), points.end());
     P va(a.x - o.x, a.y - o.y), vb(b.x - o.x, b.y - o.y);
     o = points[0];
     return va.cross(vb) &gt; 0 || (va.cross(vb) == 0 && va.length() < vb.length());
}
 
| width="10px" |
| width="50%"  |
   
   
  vector&lt;P&gt; convexHull(vector&lt;P&gt; &p) {
     sort(points.begin() + 1, points.end(), compareByAngle);
    sort(p.begin(), p.end(), compareByCoords);
    o = p[0];
     sort(p.begin() + 1, p.end(), compareByAngle);
   
   
     vector&lt;P&gt; hull;
     vector<Point> hull;
     for (int i = 0; i &lt; p.size(); i++) {
     for (int i = 0; i < points.size(); i++) {
         while (hull.size() &gt;= 2) {
         while (hull.size() >= 2) {
             P &o = hull[hull.size() - 2], &a = hull[hull.size() - 1], &b = p[i];
             Point &a = hull[hull.size() - 2], &b = hull[hull.size() - 1], &c = points[i];
             P oa(a.x - o.x, a.y - o.y), ob(b.x - o.x, b.y - o.y);
             Point ab(a, b), ac(a, c);
             if (oa.cross(ob) &lt;= 0)
             if (ab.crossProduct(ac) <= 0)
                 hull.pop_back();
                 hull.pop_back();
             else
             else
                 break;
                 break;
         }
         }
         hull.push_back(p[i]);
         hull.push_back(points[i]);
     }
     }
     return hull;
     return hull;
  }
  }
|}
== Ссылки на задачи ==
* [http://acmp.ru/?main=task&id_task=374 ACMP #374 &mdash; Выпуклая оболочка - 2]
* [http://informatics.mccme.ru/mod/statements/view3.php?chapterid=290 MCCME #290 &mdash; Выпуклая оболочка (периметр и площадь)]
* [http://informatics.mccme.ru/mod/statements/view3.php?chapterid=638 MCCME #638 &mdash; Выпуклая оболочка - периметр]


== Ссылки ==
== Ссылки ==
* [http://informatics.mccme.ru/course/view.php?id=22 informatics.mccme.ru &mdash; Курс &laquo;Геометрия&raquo; &mdash; часть 3]
Теория:
* [http://e-maxx.ru/algo/convex_hull_graham e-maxx.ru — Построение выпуклой оболочки обходом Грэхэма]
* [https://cp-algorithms.com/geometry/grahams-scan-convex-hull.html cp-algorithms.com — Convex Hull construction using Graham's Scan]
* algorithmica.org — Выпуклая оболочка: [https://algorithmica.org/ru/convex-hulls 1], [https://ru.algorithmica.org/cs/convex-hulls/graham/ 2]
* [http://e-maxx.ru/bookz/files/andreeva.pdf Андреева Е. В., Егоров Ю. Е. Вычислительная геометрия на плоскости]
* [http://www.cs.princeton.edu/courses/archive/fall12/cos226/lectures/21ElementarySorts.pdf www.cs.princeton.edu/~cos226/lectures &mdash; 2.1 Elementary Sorts]
* [http://www.cs.princeton.edu/courses/archive/fall12/cos226/lectures/21ElementarySorts.pdf www.cs.princeton.edu/~cos226/lectures &mdash; 2.1 Elementary Sorts]
* [http://e-maxx.ru/bookz/files/andreeva.pdf Андреева Е. В., Егоров Ю. Е. Вычислительная геометрия на плоскости]
* [https://usaco.guide/plat/convex-hull?lang=cpp usaco.guide — Convex Hull]
Демонстрация:
* [http://visualgo.net/en/convexhull VisuAlgo &mdash; Convex Hull]
* [http://visualgo.net/en/convexhull VisuAlgo &mdash; Convex Hull]
* [http://github.com/ADJA/algos/blob/master/Geometry/convex_hull_graham_scan.cpp Algos &mdash; Graham scan]
Код:
* [https://github.com/indy256/codelibrary/blob/master/cpp/geometry/convex_hull.cpp indy256/codelibrary/cpp/geometry/convex_hull.cpp]
* [http://github.com/ADJA/algos/blob/master/Geometry/convex_hull_graham_scan.cpp ADJA/algos/Geometry/convex_hull_graham_scan.cpp]
* [https://github.com/kevin-wayne/algs4/blob/master/src/main/java/edu/princeton/cs/algs4/GrahamScan.java kevin-wayne/algs4/GrahamScan.java]
Задачи:
* [http://informatics.mccme.ru/course/view.php?id=22 informatics.mccme.ru &mdash; Курс &laquo;Геометрия&raquo; &mdash; часть 3]
* [http://informatics.mccme.ru/mod/statements/view3.php?chapterid=290 MCCME #290 &mdash; Выпуклая оболочка (периметр и площадь)]
* [http://informatics.mccme.ru/mod/statements/view3.php?chapterid=638 MCCME #638 &mdash; Выпуклая оболочка - периметр]
* [http://acmp.ru/?main=task&id_task=374 ACMP #374 &mdash; Выпуклая оболочка - 2]


[[Категория:Геометрия]]
[[Категория:Геометрия]]

Версия от 10:05, 12 октября 2021

  • Любая экстремальная точка (например, самая левая из самых нижних) всегда принадлежит выпуклой оболочке. Сортируем точки по координатам, выбираем экстремальную точку O.
  • Сортируем остальные почки по полярному углу от O. Точка A должна идти раньше точки B, если поворот от вектора OA к вектору OB происходит против часовой стрелки (косое произведение положительно). Если OA и OB коллинеарны, то раньше идёт точка, ближайшая к O.
  • Добавляем точку O в оболочку.
  • Рассматриваем остальные точки в порядке сортировки по углу. Пока две последние точки оболочки вместе с новой точкой лежат на одной прямой или дают поворот по часовой стрелке (косое произведение неотрицательно), выкидываем последнюю точку из оболочки. Добавляем следующую точку в оболочку.
struct Point {
    double x, y;

    Point() {}

    Point(const Point &a, const Point &b) : x(b.x - a.x), y(b.y - a.y) {}

    bool operator < (const Point &that) const {
        return y < that.y || y == that.y && x < that.x;
    }

    double length() const {
        return hypot(x, y);
    }

    double crossProduct(const Point &that) const {
        return x * that.y - y * that.x;
    }
};

Point o;
bool compareByAngle(const Point &a, const Point &b) {
    Point oa(o, a), ob(o, b);
    return oa.crossProduct(ob) > 0 || oa.crossProduct(ob) == 0 && oa.length() < ob.length();
}

vector<Point> convexHull(vector<Point> &points) {
    sort(points.begin(), points.end());
    o = points[0];

    sort(points.begin() + 1, points.end(), compareByAngle);

    vector<Point> hull;
    for (int i = 0; i < points.size(); i++) {
        while (hull.size() >= 2) {
            Point &a = hull[hull.size() - 2], &b = hull[hull.size() - 1], &c = points[i];
            Point ab(a, b), ac(a, c);
            if (ab.crossProduct(ac) <= 0)
                hull.pop_back();
            else
                break;
        }
        hull.push_back(points[i]);
    }
    return hull;
}

Ссылки

Теория:

Демонстрация:

Код:

Задачи: