CodeForces 340B Maximal Area Quadrilateral(凸包+旋转卡壳)

题意:给n (4 ≤ n ≤ 300)个点,求最大四边形面积。


分析:

   此题点数太少,n3可过,枚举对角线,求对角线两边最大三角形。

   不过还有一个更快的方法   就是凸包+旋转卡壳。

   如果凸包只有三个点,则枚举三个点和其他点构成的最大四边形。

  如果凸包大于三个点,则直接旋转卡壳求最大四边形。



#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iomanip>
#include<sstream>
#include<limits>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const ll INF = 1e18;
const int maxn = 2e5+10;
const ll MOD = 1000000007;
const double EPS = 1e-10;
const double Pi = acos(-1.0);

#define Vector Point

int dcmp(double x) { return fabs(x) < EPS ? 0 : (x < 0 ? -1 : 1); }
struct Point {
    double x, y;

    Point(const Point& rhs): x(rhs.x), y(rhs.y) { } //拷贝构造函数
    Point(double x = 0.0, double y = 0.0): x(x), y(y) { }   //构造函数

    friend Vector operator + (const Vector& A, const Vector& B) { return Vector(A.x+B.x, A.y+B.y); }
    friend Vector operator - (const Point& A, const Point& B) { return Vector(A.x-B.x, A.y-B.y); }
    friend Vector operator * (const Vector& A, const double& p) { return Vector(A.x*p, A.y*p); }
    friend Vector operator / (const Vector& A, const double& p) { return Vector(A.x/p, A.y/p); }
    friend bool operator == (const Point& A, const Point& B) { return dcmp(A.x-B.x) == 0 && dcmp(A.y-B.y) == 0; }
    friend bool operator < (const Point& A, const Point& B) { return A.x < B.x || (A.x == B.x && A.y < B.y); }
};
double Cross(const Vector& A, const Vector& B) { return A.x*B.y - A.y*B.x; }    //叉积

vector<Point> p;
vector<Point> ConvexHull()
{
    //预处理,删除重复点
    sort(p.begin(), p.end());
    p.erase(unique(p.begin(), p.end()), p.end());
    int n = p.size(), m = 0;
    vector<Point> res(n+1);
    for(int i = 0; i < n; i++) {
        while(m > 1 && Cross(res[m-1]-res[m-2], p[i]-res[m-2]) <= 0) m--;
        res[m++] = p[i];
    }
    int k = m;
    for(int i = n-2; i >= 0; i--) {
        while(m > k && Cross(res[m-1]-res[m-2], p[i]-res[m-2]) <= 0) m--;
        res[m++] = p[i];
    }
    m -= n > 1;
    res.resize(m);
    return res;
}
double Area(Point p1,Point p2,Point p3)   //这里求的面积没*0.5
{
    return abs(Cross(p1,p2)+Cross(p2,p3)+Cross(p3,p1));
}
vector<Point> ans;
int main(){
#ifdef LOCAL
	freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);
	//freopen("output.txt","w",stdout);
#endif
//ios_base::sync_with_stdio(0);
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        p.clear();ans.clear();
        for(int i = 0; i < n; i++)
        {
            double x,y;
            scanf("%lf %lf",&x,&y);
            p.push_back(Point(x,y));
        }
        ans = ConvexHull() ;
        double res = 0;
        if (ans.size() >= 4)
        {
            int top = ans.size();
            for(int i = 0;i < top;i++)  //旋转卡壳
            {
                int j = (i+2)%top;
                int k = (i+1)%top;
                int h = (j+1)%top;

                while(Area(ans[i],ans[j],ans[k+1]) > Area(ans[i],ans[j],ans[k])) k = (k+1)%top;
                double max1 = Area(ans[i],ans[j],ans[k]);

                while(Area(ans[i],ans[j],ans[h+1]) > Area(ans[i],ans[j],ans[h])) h = (h+1)%top;
                double max2 = Area(ans[i],ans[j],ans[h]);

                double ans1 = 0;
                while(max1 + max2 > ans1)
                {
                    j = (j+1)%top;
                    ans1 = max1+max2;
                    while(Area(ans[i],ans[j],ans[k+1]) > Area(ans[i],ans[j],ans[k])) k = (k+1)%top;
                    max1 = Area(ans[i],ans[j],ans[k]);

                    while(Area(ans[i],ans[j],ans[h+1]) > Area(ans[i],ans[j],ans[h])) h = (h+1)%top;
                    max2 = Area(ans[i],ans[j],ans[h]);
                }
                res = max(res,ans1);
            }
        }
        else
        {
            for(int i = 0; i < p.size(); i++)
            {
                if (p[i] == ans[0] || p[i] == ans[1] || p[i] == ans[2]) continue;
                res = max(res,Area(ans[0],ans[1],p[i])+Area(ans[0],ans[2],p[i]));
                res = max(res,Area(ans[0],ans[1],p[i])+Area(ans[1],ans[2],p[i]));
                res = max(res,Area(ans[1],ans[2],p[i])+Area(ans[0],ans[2],p[i]));
            }
        }

        printf("%.9f\n",res*0.5);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值