【BZOJ1069】【SCOI2007】最大土地面积 凸包 单调性

链接:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/46591735");
}

题解:

先求凸包,然后:

枚举点 i ,然后对于 点 j 得到的 i j (有序) 中间的点,以及 j i (有序) 中间的点,都是单调的。

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 2050
#define eps 1e-7
using namespace std;
struct Point
{
    double x,y;
    void read(){scanf("%lf%lf",&x,&y);}
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    bool operator < (const Point &A)const
    {return x==A.x?y<A.y:x<A.x;}
    double operator - (const Point &A)const
    {return sqrt((x-A.x)*(x-A.x)+(y-A.y)*(y-A.y));}
}p[N],Zero;
int n;

double xmul(const Point &A,const Point &B,const Point &C)
{return (C.y-A.y)*(B.x-A.x)-(B.y-A.y)*(C.x-A.x);}

struct qiu_tu_bao
{// 名字就是这么屌,不服你来打我啊
    int stk1[N],top1,stk2[N],top2;
    Point tp[N];
    void work()
    {
        int i;

        stk1[top1=1]=1;
        for(i=2;i<=n;i++)
        {
            while(top1>1&&xmul(p[stk1[top1-1]],p[stk1[top1]],p[i])>-eps)top1--;
            stk1[++top1]=i;
        }
        stk2[top2=1]=n;
        for(i=n-1;i;i--)
        {
            while(top2>1&&xmul(p[stk2[top2-1]],p[stk2[top2]],p[i])>-eps)top2--;
            stk2[++top2]=i;
        }
        n=0;
        for(i=1;i<top1;i++)tp[++n]=p[stk1[i]];
        for(i=1;i<top2;i++)tp[++n]=p[stk2[i]];
        memcpy(p,tp,sizeof(Point)*(n+1));
    }
}qtb;

int f[N][N];
#define rig(x,y) ((x+y - 1)%n+1)
#define lef(x,y) ((x-y+n-1)%n+1)
inline double Area(int l,int r,int x)
{
    double ret=xmul(Zero,p[l],p[r]);
    ret+=xmul(Zero,p[r],p[x]);
    ret+=xmul(Zero,p[x],p[l]);
    return ret;
}
inline bool check(int l,int r,int a,int b)
{return Area(l,r,a)<Area(l,r,b);}
int main()
{
    int i,j,k;
    int a,b,c;
    Zero=Point(0,0);

    scanf("%d",&n);
    for(i=1;i<=n;i++)p[i].read();
    sort(p+1,p+n+1);
    qtb.work();

    for(i=1;i<=n;i++)
    {
        f[i][rig(i,2)]=rig(i,1);
        for(j=rig(i,3);rig(j,1)!=i;j=rig(j,1))
        {
            f[i][j]=f[i][lef(j,1)];
            while(rig(f[i][j],1)!=j&&
                check(i,j,f[i][j],f[i][j]+1))f[i][j]++;
        }
    }
    double ans=0.0;
    for(i=1;i<=n;i++)for(j=rig(i,2);rig(j,1)!=i;j=rig(j,1))
        ans=max(ans,Area(i,j,f[i][j])+Area(i,f[j][i],j));
    printf("%.3lf\n",ans/2.0);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值