Выпуклая оболочка: различия между версиями
Перейти к навигации
Перейти к поиску
Ctrlalt (обсуждение | вклад) Нет описания правки |
Ctrlalt (обсуждение | вклад) Нет описания правки |
||
| Строка 23: | Строка 23: | ||
} | } | ||
}; | }; | ||
vector<Point> convexHull(vector<Point> &points) { | vector<Point> convexHull(vector<Point> &points) { | ||
sort(points.begin(), points.end()); | sort(points.begin(), points.end()); | ||
sort(points.begin() + 1, points.end(), [&](Point &a, Point &b) { | |||
Point &o = points[0], oa(o, a), ob(o, b); | |||
sort(points.begin() + 1, points.end(), | return oa.crossProduct(ob) > 0 || oa.crossProduct(ob) == 0 && oa.length() < ob.length(); | ||
}); | |||
vector<Point> hull; | vector<Point> hull; | ||
for ( | for (Point &p : points) { | ||
while (hull.size() >= 2) { | while (hull.size() >= 2) { | ||
Point &a = hull[hull.size() - 2], &b = hull[hull.size() - 1 | Point &a = hull[hull.size() - 2], &b = hull[hull.size() - 1]; | ||
Point ab(a, b), ac(a, | Point ab(a, b), ac(a, p); | ||
if (ab.crossProduct( | if (ab.crossProduct(ap) <= 0) | ||
hull.pop_back(); | hull.pop_back(); | ||
else | else | ||
break; | break; | ||
} | } | ||
hull.push_back( | hull.push_back(p); | ||
} | } | ||
return hull; | return hull; | ||
Версия от 11:26, 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) {
sort(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), ac(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
Задачи: