bzoj3707: 圈地

题目描述:

$2$ 维平面上有 $n$ 个木桩,黄学长有一次圈地的机会并得到圈到的土地,为了体现他的高风亮节,他要使他圈到的土地面积尽量小。圈地需要圈一个至少 $3$ 个点的多边形,多边形的顶点就是一个木桩,圈得的土地就是这个多边形内部的土地。(因为黄学长非常的神,所以他允许圈出的第 $n$ 点共线,那样面积算 $0$)

思路:

枚举每一条边,考虑这条边作为y轴坐标的大小排序,把边按斜率排序,每次转换边的时候之有这条边的两个端点的大小相对位置会发生变化,排名互换,维护这种变化。

以下代码:

#include<bits/stdc++.h>
#define il inline
#define db double
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=1005;
db ans=1e60;
int n,tot,pos[N],rk[N];
struct node{
    db x,y;
}t[N];
struct data{
    int x,y;db k;
}f[N*N];
il int read(){
    int x,f=1;char ch;
    _(!)ch=='-'?f=-1:f;x=ch^48;
    _()x=(x<<1)+(x<<3)+(ch^48);
    return f*x;
}
bool cmp(node t1,node t2){
    return (t1.x<t2.x);
}
bool cmp1(data t1,data t2){
    return t1.k<t2.k;
}
node operator-(node a,node b){
    return (node){a.x-b.x,a.y-b.y};
}
il db cross(node a,node b){
    return a.x*b.y-a.y*b.x;
}
il db cal(int a,int b,int c){
    return cross(t[a]-t[c],t[b]-t[c]);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)t[i].x=read(),t[i].y=read();
    sort(t+1,t+1+n,cmp);
    for(int i=1;i<n;i++){
        for(int j=i+1;j<=n;j++){
            f[++tot].x=i;f[tot].y=j;
            f[tot].k=(t[j].y-t[i].y)/(t[j].x-t[i].x);
        }
    }
    for(int i=1;i<=n;i++)pos[i]=rk[i]=i;
    sort(f+1,f+1+tot,cmp1);
    for(int i=1;i<=tot;i++){
        int x=f[i].x,y=f[i].y;
        if(pos[x]>pos[y])swap(x,y);
        if(pos[x]>1)
            ans=fmin(ans,fabs(cal(x,y,rk[pos[x]-1])));
        if(pos[y]<n)
            ans=fmin(ans,fabs(cal(x,y,rk[pos[y]+1])));
        swap(pos[x],pos[y]);
        swap(rk[pos[x]],rk[pos[y]]);
    }
    printf("%.2lf\n",ans/2.0);
    return 0;
}
View Code

 

posted @ 2019-03-07 00:02  Jessiejzy  阅读(277)  评论(0编辑  收藏  举报