• 【BZOJ3707】圈地 几何


    【BZOJ3707】圈地

    Description

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

    Input

    第一行一个整数n,表示木桩个数。
    接下来n行,每行2个整数表示一个木桩的坐标,坐标两两不同。

    Output

    仅一行,表示最小圈得的土地面积,保留2位小数。

    Sample Input

    3
    0 0
    0 1
    1 0

    Sample Output

    0.50

    HINT

    对于100%的数据,n<=1000。

    题解:假如我们已经确定了三角形的一条边,那么面积可以表示成 边长*高/2,如果我们将所选的边当做y轴,那么显然第3个点应取|x|最小的点。问题是如何快速确定|x|最小的点。

    有一个结论(难想),就是将所有直线按照极角排序(斜率也行),将所有点按y排序(相当于所选的边是x轴),此时所有点距离直线的相对位置是确定的。我们枚举每条直线,当我们从ai,bi枚举到ai+1,bi+1时,只有ai,bi的相对位置发生了改变,其余点的相对位置均不改变。(相对位置指的是以所选直线为y轴后,x的大小关系。这个结论自己画画应该就能理解)

    于是我们用桶维护每个点的相对位置即可。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const int maxn=1010;
    int n,tot;
    int s[maxn],pos[maxn];
    double ans;
    struct point
    {
    	double x,y;
    	point () {}
    	point (double a,double b){x=a,y=b;}
    	point operator + (const point &a) const {return point(x+a.x,y+a.y);}
    	point operator - (const point &a) const {return point(x-a.x,y-a.y);}
    	double operator * (const point &a) const {return x*a.y-y*a.x;}
    }p[maxn];
    struct line
    {
    	double k;
    	int a,b;
    }l[1000000];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    bool cmpy(point a,point b)
    {
    	return a.y<b.y;
    }
    bool cmpk(line a,line b)
    {
    	return a.k<b.k;
    }
    void calc(int a,int b,int c)
    {
    	double S=fabs((p[b]-p[a])*(p[c]-p[a])/2);
    	ans=min(ans,S);
    }
    int main()
    {
    	n=rd();
    	int i,j;
    	for(i=1;i<=n;i++)	p[i].x=rd(),p[i].y=rd();
    	sort(p+1,p+n+1,cmpy);
    	for(i=1;i<=n;i++)	s[i]=pos[i]=i;
    	for(i=1;i<=n;i++)	for(j=i+1;j<=n;j++)	l[++tot].k=atan2(p[j].y-p[i].y,p[j].x-p[i].x),l[tot].a=i,l[tot].b=j;
    	sort(l+1,l+tot+1,cmpk);
    	ans=999999999;
    	for(i=1;i<=tot;i++)
    	{
    		if(pos[l[i].a]>pos[l[i].b])	swap(l[i].a,l[i].b);
    		if(pos[l[i].a]>1)	calc(s[pos[l[i].a]-1],l[i].a,l[i].b);
    		if(pos[l[i].b]<n)	calc(s[pos[l[i].b]+1],l[i].a,l[i].b);
    		swap(pos[l[i].a],pos[l[i].b]);
    		s[pos[l[i].a]]=l[i].a,s[pos[l[i].b]]=l[i].b;
    	}
    	printf("%.2lf",ans);
    	return 0;
    }
  • 相关阅读:
    控制语句
    (小程序)接收用户键盘输入
    运算符
    java doc形成注释文档
    linux中rz、sz命令,zip、unzip命令,sqlite3基本操作
    hash应用-加随机盐保存密码
    非对称/对称加密算法,hash算法
    自签名的应用--数字货币
    HTTPS原理
    Django中app的model相互引用问题
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7501125.html
Copyright © 2020-2023  润新知