POJ 2079 最大三角形面积(凸包)

Triangle

Description

Given n distinct points on a plane, your task is to find the triangle that have the maximum area, whose vertices are from the given points.

Input

The input consists of several test cases. The first line of each test case contains an integer n, indicating the number of points on the plane. Each of the following n lines contains two integer xi and yi, indicating the ith points. The last line of the input is an integer −1, indicating the end of input, which should not be processed. You may assume that 1 <= n <= 50000 and −104 <= xi, yi <= 104for all i = 1 . . . n.

Output

For each test case, print a line containing the maximum area, which contains two digits after the decimal point. You may assume that there is always an answer which is greater than zero.

Sample Input

3
3 4
2 6
2 7
5
2 6
3 9
2 0
8 0
6 5
-1

Sample Output

0.50
27.00

Source

凸包三角:求N个点组成的三角形的最大面积?

思路:

不难想到最大三角形一定由凸包的顶点构成,难点在于怎么搜索。O(N^3)枚举会超时,旋转卡壳法O(N^2)解决问题。

点的移动:先固定一条边(红色实线),然后依次搜索第3个顶点1st,三角形面积必然是先增后减的,一旦发现开始减小了,立即终止搜索,转而移动固定边。

边的移动:固定边的移动也有讲究,固定边两点的跨度用add表示的话,add不一定是1,最大可达到(N + 1)/2,于是将此add也枚举一遍即可。

代码:

  1 #include "cstdio"
  2 #include "map"
  3 #include "cmath"
  4 #include "queue"
  5 #include "vector"
  6 #include "string"
  7 #include "cstring"
  8 #include "iostream"
  9 #include "algorithm"
 10 #define db double
 11 #define ll long long
 12 #define vec vector<ll>
 13 #define mt  vector<vec>
 14 #define ci(x) scanf("%d",&x)
 15 #define cd(x) scanf("%lf",&x)
 16 #define cl(x) scanf("%lld",&x)
 17 #define pi(x) printf("%d
",x)
 18 #define pd(x) printf("%f
",x)
 19 #define pl(x) printf("%lld
",x)
 20 //#define rep(i, x, y) for(int i=x;i<=y;i++)
 21 #define rep(i,n) for(int i=0;i<n;i++)
 22 const int N   = 1e5 + 5;
 23 const int mod = 1e9 + 7;
 24 const int mOD = mod - 1;
 25 const db  eps = 1e-10;
 26 const db  PI  = acos(-1.0);
 27 const int inf=0x3f3f3f3f;
 28 using namespace std;
 29 struct P
 30 {
 31     db x, y;
 32     P() {}
 33     P(db x, db y) : x(x), y(y) {}
 34     P operator + (P p){ return P(x + p.x, y + p.y); }
 35     P operator - (P p){ return P(x - p.x, y - p.y); }
 36     P operator * (db d){ return P(x*d, y*d); }
 37     bool operator < (const P& a) const
 38     {
 39         if (x != a.x) return x < a.x;
 40         else return y < a.y;
 41     }
 42     db dot(P p) { return x*p.x + y*p.y; }
 43     db det(P p) { return x*p.y - y*p.x; }
 44 };
 45 
 46 P p[N];
 47 // 向量AB 与 AC 的叉积 如果叉积大于0,那么C在向量AB的逆时针方向,叉积小于0则在AB的顺时针方向。如果叉积等于0,则ABC共线。
 48 db cross(P A, P B, P C) {return (B - A).det(C - A); }
 49 // AB和AC构成的平行四边形面积
 50 db Area(P A, P B, P C)  {return abs(cross(A, B, C)); }
 51 // 求凸包
 52 vector <P> ch(P *ps, int n)
 53 {
 54     sort(ps, ps + n);
 55     int k = 0;   // 凸包的顶点数
 56     vector <P> qs(n * 2);   // 构造中的凸包
 57     for (int i = 0; i < n; ++i)
 58     {
 59         while (k > 1 && (qs[k - 1] - qs[k - 2]).det(ps[i] - qs[k - 1]) <= 0)
 60             --k;
 61         qs[k++] = ps[i];
 62     }
 63     for (int i = n - 2, t = k; i >= 0; --i)
 64     {
 65         while (k > t && (qs[k - 1] - qs[k - 2]).det(ps[i] - qs[k - 1]) <= 0)
 66             --k;
 67         qs[k++] = ps[i];
 68     }
 69     qs.resize(k - 1);
 70     return qs;
 71 }
 72 
 73 int main()
 74 {
 75     int n;
 76     while (~scanf("%d", &n) && n > 0)
 77     {
 78         for(int i = 0; i < n; ++i) cd(p[i].x),cd(p[i].y);
 79         vector <P> ps = ch(p, n);
 80         n = ps.size();
 81         db ans = 0;
 82         for(int ad = 1; ad < (n + 1) / 2; ++ad)
 83         {
 84             int k = (ad + 1) % n;
 85             for(int i = 0; i < n; ++i)
 86             {
 87                 int j = (i + ad) % n;
 88                 db prev = Area(ps[i], ps[j], ps[k]);
 89                 for(++k; k != j && k != i; ++k)
 90                 {
 91                     if (k == n) k = 0;
 92                     db cur = Area(ps[i], ps[j], ps[k]);
 93                     ans = max(ans, prev);
 94                     if (cur <= prev) break;    // 达到极值
 95                     prev = cur;
 96                 }
 97                 --k;                    // 退出循环时,其实k已经超了一个,这里减回来
 98                 if(k == -1) k += n;
 99             }
100         }
101         printf("%.2f
", ans / 2);
102     }
103     return 0;
104 }
原文地址:https://www.cnblogs.com/mj-liylho/p/8431453.html