[BZOJ1069][SCOI2007][凸包][旋转卡壳]最大土地面积
2014-05-06 17:02
453 查看
[Problem Description]
在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大。
[Algorithm]
凸包 旋转卡壳
[Analysis]
首先选择的这4个点一定在凸包上,所以先求一下凸包。然后枚举四边形的其中一条对角线,然后想办法求出对角线两侧使得四边形面积最大的两个点。假设枚举对角线的时候固定一个点,另一个点顺时针转动,则最优的另外两个点也一定是顺时针转动的。所以边枚举边更新,旋转卡壳的思想。这样的话整个算法的时间复杂度为O(n^2)
[Pay Attention]
注意精度问题和枚举的时候边界问题
[To Myself]
这种几何中的多边形上枚举的题都可以考虑一下旋转卡壳来降低复杂度
[code]/************************************************************** Problem: 1069 User: gaotianyu1350 Language: C++ Result: Accepted Time:192 ms Memory:1316 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const double EPS = 1e-5; const int MAXN = 2100; inline int dcmp(double a, double b) { if (fabs(a - b) < EPS) return 0; return a > b ? 1 : -1; } struct point { double x, y; bool operator < (const point a) const { return (!dcmp(x, a.x) && dcmp(y, a.y) < 0) || dcmp(x, a.x) < 0; } }; inline double dmax(double a, double b) { return a > b ? a : b; } inline double cross(point a, point b, point c) { return (b.x - a.x) * (c.y - b.y) - (c.x - b.x) * (b.y - a.y); } inline double area(point a, point b, point c) { return fabs(cross(a, b, c)); } point p[MAXN]; int t[MAXN], cnt = 0; int n; inline void MakeTubao() { sort(p + 1, p + 1 + n); for (int i = 1; i <= n; i++) { while (cnt > 1 && dcmp(cross(p[t[cnt - 1]], p[t[cnt]], p[i]), 0) >= 0) cnt--; t[++cnt] = i; } int temp = cnt; for (int i = n - 1; i >= 1; i--) { while (cnt > temp && dcmp(cross(p[t[cnt - 1]], p[t[cnt]], p[i]), 0) >= 0) cnt--; t[++cnt] = i; } if (n > 1) cnt--; } inline double Solve(int st) { double ans = 0; t[cnt + 1] = t[1]; int q1 = st, q2 = st + 2; for (int j = st + 2; j <= cnt; j++) { if (st == 1 && j == cnt) continue; while (dcmp(area(p[t[st]], p[t[j]], p[t[q1 + 1]]), area(p[t[st]], p[t[j]], p[t[q1]])) >= 0) q1 = q1 % cnt + 1; while (dcmp(area(p[t[st]], p[t[j]], p[t[q2 + 1]]), area(p[t[st]], p[t[j]], p[t[q2]])) >= 0) q2 = q2 % cnt + 1; ans = dmax(ans, area(p[t[st]], p[t[j]], p[t[q1]]) + area(p[t[st]], p[t[j]], p[t[q2]])); } return ans; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y); MakeTubao(); double ans = 0; for (int i = 1; i <= n - 2; i++) { double temp = Solve(i); ans = dmax(ans, temp); } printf("%.3f\n", ans / 2); }
在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大。
[Algorithm]
凸包 旋转卡壳
[Analysis]
首先选择的这4个点一定在凸包上,所以先求一下凸包。然后枚举四边形的其中一条对角线,然后想办法求出对角线两侧使得四边形面积最大的两个点。假设枚举对角线的时候固定一个点,另一个点顺时针转动,则最优的另外两个点也一定是顺时针转动的。所以边枚举边更新,旋转卡壳的思想。这样的话整个算法的时间复杂度为O(n^2)
[Pay Attention]
注意精度问题和枚举的时候边界问题
[To Myself]
这种几何中的多边形上枚举的题都可以考虑一下旋转卡壳来降低复杂度
[code]/************************************************************** Problem: 1069 User: gaotianyu1350 Language: C++ Result: Accepted Time:192 ms Memory:1316 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const double EPS = 1e-5; const int MAXN = 2100; inline int dcmp(double a, double b) { if (fabs(a - b) < EPS) return 0; return a > b ? 1 : -1; } struct point { double x, y; bool operator < (const point a) const { return (!dcmp(x, a.x) && dcmp(y, a.y) < 0) || dcmp(x, a.x) < 0; } }; inline double dmax(double a, double b) { return a > b ? a : b; } inline double cross(point a, point b, point c) { return (b.x - a.x) * (c.y - b.y) - (c.x - b.x) * (b.y - a.y); } inline double area(point a, point b, point c) { return fabs(cross(a, b, c)); } point p[MAXN]; int t[MAXN], cnt = 0; int n; inline void MakeTubao() { sort(p + 1, p + 1 + n); for (int i = 1; i <= n; i++) { while (cnt > 1 && dcmp(cross(p[t[cnt - 1]], p[t[cnt]], p[i]), 0) >= 0) cnt--; t[++cnt] = i; } int temp = cnt; for (int i = n - 1; i >= 1; i--) { while (cnt > temp && dcmp(cross(p[t[cnt - 1]], p[t[cnt]], p[i]), 0) >= 0) cnt--; t[++cnt] = i; } if (n > 1) cnt--; } inline double Solve(int st) { double ans = 0; t[cnt + 1] = t[1]; int q1 = st, q2 = st + 2; for (int j = st + 2; j <= cnt; j++) { if (st == 1 && j == cnt) continue; while (dcmp(area(p[t[st]], p[t[j]], p[t[q1 + 1]]), area(p[t[st]], p[t[j]], p[t[q1]])) >= 0) q1 = q1 % cnt + 1; while (dcmp(area(p[t[st]], p[t[j]], p[t[q2 + 1]]), area(p[t[st]], p[t[j]], p[t[q2]])) >= 0) q2 = q2 % cnt + 1; ans = dmax(ans, area(p[t[st]], p[t[j]], p[t[q1]]) + area(p[t[st]], p[t[j]], p[t[q2]])); } return ans; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y); MakeTubao(); double ans = 0; for (int i = 1; i <= n - 2; i++) { double temp = Solve(i); ans = dmax(ans, temp); } printf("%.3f\n", ans / 2); }
相关文章推荐
- BZOJ 1069 [SCOI 2007] 最大土地面积 (凸包+旋转卡壳)
- [Bzoj1069][Scoi2007]最大土地面积(凸包)(旋转卡壳)
- BZOJ 1069 SCOI 2007 最大土地面积 凸包+旋转卡壳
- BZOJ1069 [SCOI2007]最大土地面积 【凸包 + 旋转卡壳】
- [BZOJ 1069][SCOI 2007]最大土地面积(凸包+旋转卡壳)
- bzoj 1069: [SCOI2007]最大土地面积 凸包+旋转卡壳
- bzoj1069 [SCOI2007]最大土地面积(凸包+旋转卡壳)
- [BZOJ1069][SCOI2007]最大土地面积(凸包+旋转卡壳)
- [BZOJ]1069 [SCOI2007] 最大土地面积 凸包 + 旋转卡壳
- 【bzoj1069】[SCOI2007]最大土地面积 凸包+旋转卡壳
- 【BZOJ 1069】【SCOI 2007】最大土地面积 凸包+旋转卡壳
- BZOJ 1069: [SCOI2007]最大土地面积 凸包,旋转卡壳
- 【BZOJ】1069: [SCOI2007]最大土地面积(凸包+旋转卡壳)
- [BZOJ1069][SCOI2007]最大土地面积 凸包+旋转卡壳
- [BZOJ1069]SCOI2007最大土地面积|凸包|旋转卡壳
- [省选前题目整理][BZOJ 1069][SCOI 2007]最大土地面积(旋转卡壳)
- BZOJ 1069: [SCOI2007]最大土地面积 [旋转卡壳]
- bzoj 1069: [SCOI2007]最大土地面积 (旋转卡壳)
- BZOJ 1069: [SCOI2007]最大土地面积 旋转卡壳
- bzoj 1069 [SCOI2007]最大土地面积(旋转卡壳)