Выпуклая оболочка: различия между версиями
Перейти к навигации
Перейти к поиску
Ctrlalt (обсуждение | вклад) (→Ссылки) |
Ctrlalt (обсуждение | вклад) Нет описания правки |
||
(не показано 5 промежуточных версий этого же участника) | |||
Строка 1: | Строка 1: | ||
* Любая экстремальная точка (например, самая левая из самых нижних) всегда принадлежит выпуклой оболочке. Сортируем точки по координатам, выбираем экстремальную точку O. | * Любая экстремальная точка (например, самая левая из самых нижних) всегда принадлежит выпуклой оболочке. Сортируем точки по координатам, выбираем экстремальную точку O. | ||
* Сортируем остальные почки по полярному углу от O. Точка A должна идти раньше точки B, если поворот от вектора OA к вектору OB происходит | * Сортируем остальные почки по полярному углу от O. Точка A должна идти раньше точки B, если поворот от вектора OA к вектору OB происходит против часовой стрелки (косое произведение положительно). Если OA и OB коллинеарны, то раньше идёт точка, ближайшая к O. | ||
* Добавляем точку O в оболочку. | * Добавляем точку O в оболочку. | ||
* Рассматриваем остальные точки в порядке сортировки по углу. Пока две последние точки оболочки вместе с новой точкой лежат на одной прямой или дают поворот по часовой стрелке (косое произведение неотрицательно), выкидываем последнюю точку из оболочки. Добавляем следующую точку в оболочку. | * Рассматриваем остальные точки в порядке сортировки по углу. Пока две последние точки оболочки вместе с новой точкой лежат на одной прямой или дают поворот по часовой стрелке (косое произведение неотрицательно), выкидываем последнюю точку из оболочки. Добавляем следующую точку в оболочку. | ||
struct Point { | |||
double x, y; | |||
struct | Point() {} | ||
double x, 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 | return hypot(x, y); | ||
} | } | ||
double | |||
return x * | double crossProduct(const Point &that) const { | ||
} | return x * that.y - y * that.x; | ||
} | |||
}; | }; | ||
vector<Point> convexHull(vector<Point> &points) { | |||
nth_element(points.begin(), points.begin(), points.end()); | |||
sort(points.begin() + 1, points.end(), [&](Point &a, Point &b) { | |||
Point &o = points[0], oa(o, a), ob(o, b); | |||
return oa.crossProduct(ob) > 0 || oa.crossProduct(ob) == 0 && oa.length() < ob.length(); | |||
}); | |||
vector | vector<Point> hull; | ||
for ( | for (Point &p : points) { | ||
while (hull.size() | while (hull.size() >= 2) { | ||
Point &a = hull[hull.size() - 2], &b = hull[hull.size() - 1]; | |||
Point ab(a, b), ap(a, p); | |||
if ( | if (ab.crossProduct(ap) <= 0) | ||
hull.pop_back(); | hull.pop_back(); | ||
else | else | ||
break; | break; | ||
} | } | ||
hull.push_back(p | hull.push_back(p); | ||
} | } | ||
return hull; | return hull; | ||
} | } | ||
== Ссылки | == Ссылки == | ||
* [http:// | Теория: | ||
* [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 — 2.1 Elementary Sorts] | |||
* [https://usaco.guide/plat/convex-hull?lang=cpp usaco.guide — Convex Hull] | |||
Демонстрация: | |||
* [http://visualgo.net/en/convexhull VisuAlgo — Convex Hull] | |||
Код: | |||
* [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 — Курс «Геометрия» — часть 3] | |||
* [http://informatics.mccme.ru/mod/statements/view3.php?chapterid=290 MCCME #290 — Выпуклая оболочка (периметр и площадь)] | * [http://informatics.mccme.ru/mod/statements/view3.php?chapterid=290 MCCME #290 — Выпуклая оболочка (периметр и площадь)] | ||
* [http://informatics.mccme.ru/mod/statements/view3.php?chapterid=638 MCCME #638 — Выпуклая оболочка - периметр] | * [http://informatics.mccme.ru/mod/statements/view3.php?chapterid=638 MCCME #638 — Выпуклая оболочка - периметр] | ||
* [http://acmp.ru/?main=task&id_task=374 ACMP #374 — Выпуклая оболочка - 2] | |||
* [http:// | |||
[[Категория:Геометрия]] | [[Категория:Геометрия]] |
Текущая версия от 11:47, 9 октября 2022
- Любая экстремальная точка (например, самая левая из самых нижних) всегда принадлежит выпуклой оболочке. Сортируем точки по координатам, выбираем экстремальную точку 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; } }; vector<Point> convexHull(vector<Point> &points) { nth_element(points.begin(), points.begin(), points.end()); sort(points.begin() + 1, points.end(), [&](Point &a, Point &b) { Point &o = points[0], oa(o, a), ob(o, b); return oa.crossProduct(ob) > 0 || oa.crossProduct(ob) == 0 && oa.length() < ob.length(); }); vector<Point> hull; for (Point &p : points) { while (hull.size() >= 2) { Point &a = hull[hull.size() - 2], &b = hull[hull.size() - 1]; Point ab(a, b), ap(a, p); if (ab.crossProduct(ap) <= 0) hull.pop_back(); else break; } hull.push_back(p); } return hull; }
Ссылки
Теория:
- e-maxx.ru — Построение выпуклой оболочки обходом Грэхэма
- cp-algorithms.com — Convex Hull construction using Graham's Scan
- algorithmica.org — Выпуклая оболочка: 1, 2
- Андреева Е. В., Егоров Ю. Е. Вычислительная геометрия на плоскости
- www.cs.princeton.edu/~cos226/lectures — 2.1 Elementary Sorts
- usaco.guide — Convex Hull
Демонстрация:
Код:
- indy256/codelibrary/cpp/geometry/convex_hull.cpp
- ADJA/algos/Geometry/convex_hull_graham_scan.cpp
- kevin-wayne/algs4/GrahamScan.java
Задачи: