zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    万兆铜缆--七类双绞线--光纤等内容
    [51CTO]反客为主 ,Linux 成为微软 Azure 上最流行的操作系统
    [知乎]超线程对游戏来说真的没用吗?
    SQLSERVER2017 最新补丁发布方式
    MSTSC 修改端口的简单方法 3389
    使用WinSW 将 exe 创建成Windows下面 service的方法 (将nginx创建成 services)
    [时政]在美国,是参议院议长的权力大,还是众议院议长的权力大
    内网内使用https 和 使用http 建立连接的速度对比
    Windows下 OpenSSL的安装与简单使用
    [转发]VMware厚置备延迟置零 、 厚置备置零、精简置备 区别
  • 原文地址:https://www.cnblogs.com/mj-liylho/p/8431453.html
Copyright © 2011-2022 走看看