Hướng giải của Tam giác lớn nhất nội tiếp bao lồi
Nhớ rằng hướng dẫn giải này chỉ nên sử dụng khi bế tắc, và tuyệt đối không nên sao chép mã nguồn kèm theo. Hãy tôn trọng tác giả bài tập và người viết hướng dẫn giải.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Tác giả:
Hướng dẫn giải
Ba đỉnh của tam giác có diện tích lớn nhất luôn nằm trên bao lồi. Do đó:
- Xây dựng bao lồi.
- Dùng kỹ thuật Rotating Calipers (ba con trỏ) để tìm tam giác lớn nhất:
Cố định đỉnh thứ nhất \(i\), dùng hai con trỏ \(j\) và \(k\) di chuyển quanh bao lồi. Với mỗi \(i\), tăng \(j\) cho đến khi diện tích \((i, j, k)\) không tăng thêm, rồi tăng \(k\). Cập nhật diện tích lớn nhất.
Độ phức tạp: \(O(N \log N)\) cho việc xây dựng bao lồi và \(O(N^2)\) cho tìm tam giác (hoặc \(O(N)\) với kỹ thuật ba con trỏ tinh tế).
Mã nguồn C++
#include <bits/stdc++.h>
using namespace std;
struct Point { long long x, y; };
long long cross(const Point& a, const Point& b, const Point& c) {
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}
vector<Point> build_hull(vector<Point> p) {
int n = p.size();
sort(p.begin(), p.end(), [](const Point& a, const Point& b) {
return a.x != b.x ? a.x < b.x : a.y < b.y;
});
vector<Point> hull;
for (int i = 0; i < n; i++) {
while (hull.size() >= 2 && cross(hull[hull.size()-2], hull.back(), p[i]) <= 0)
hull.pop_back();
hull.push_back(p[i]);
}
int lower = hull.size();
for (int i = n-2; i >= 0; i--) {
while (hull.size() > lower && cross(hull[hull.size()-2], hull.back(), p[i]) <= 0)
hull.pop_back();
hull.push_back(p[i]);
}
hull.pop_back();
return hull;
}
long long max_triangle_area2(const vector<Point>& hull) {
int m = hull.size();
long long ans = 0;
for (int i = 0; i < m; i++) {
int j = (i + 1) % m;
int k = (j + 1) % m;
while (j != i && k != i) {
long long cur = abs(cross(hull[i], hull[j], hull[k]));
ans = max(ans, cur);
int nk = (k + 1) % m;
if (nk == i) break;
long long nxt = abs(cross(hull[i], hull[j], hull[nk]));
if (nxt > cur) k = nk;
else {
int nj = (j + 1) % m;
if (nj == i) break;
j = nj;
}
}
}
return ans;
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
int n; cin >> n;
vector<Point> p(n);
for (int i = 0; i < n; i++) cin >> p[i].x >> p[i].y;
vector<Point> hull = build_hull(p);
long long area2 = max_triangle_area2(hull);
cout << fixed << setprecision(6) << area2 / 2.0 << "\n";
return 0;
}
Nhận xét