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 −10 4 <= xi, yi <= 10 4for 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\n",x)
 18 #define pd(x) printf("%f\n",x)
 19 #define pl(x) printf("%lld\n",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\n", ans / 2);
102     }
103     return 0;
104 }

 

 

转载于:https://www.cnblogs.com/mj-liylho/p/8431453.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值