• 题解 Luogu P4166 [SCOI2007]最大土地面积


    题意

    给定 \(n\) 个点,从中选出 \(4\) 个,使得它们围成的四边形面积最大。输出面积,保留三位小数。

    \(1 \leq n \leq 2000,|x_i|,|y_i| \leq 10^6\)

    是的竟然可能 \(n<4\)...丧心病狂

    题解

    首先求个凸包,直觉告诉我们四个点都在凸包上。

    但是凸包大小小于 \(4\) 咋办?(傻眼)

    • 凸包大小小于 \(3\)

      它甚至不愿意组成一块面积...答案肯定为 \(0\)

    • 凸包大小等于 \(3\)

      这个四边形看上去比较另类...它是凹四边形。我们要做的,就是找一个不在凸包中的点和凸包的一条边构成一个最小的三角形,所求的面积就是凸包面积减去这个三角形的面积。

    • 凸包大小大于 \(3\)

      终于可以四个点都在凸包上了...感动。我们可以固定一个点,逆时针枚举四边形的对角线,然后分别去找以对角线为底,另一个顶点分别在对角线两侧的两个三角形。直觉告诉在对角线逆时针枚举的过程中,这两个点爷在逆时针运动。利用类似旋转卡壳的方法求解即可。

    # include <bits/stdc++.h>
    # define Vector Point
    # define DB double
    # define CP const Point
    # define CV const Vector
    const int N=100010,INF=0x3f3f3f3f;
    const DB eps=1e-8;
    const DB Pi=acos(-1);
    bool chosen[N];
    int idx[N];
    struct Point{
    	DB x,y;
    	Point(DB X=0,DB Y=0){
    		x=X,y=Y;
    		return;
    	}
    };
    typedef std::vector <Point> Poly;
    inline int read(void){
    	int res,f=1;
    	char c;
    	while((c=getchar())<'0'||c>'9')
    		if(c=='-')f=-1;
    	res=c-48;
    	while((c=getchar())>='0'&&c<='9')
    		res=res*10+c-48;
    	return res*f;
    }
    inline int Sign(DB x){
    	return (x<-eps)?-1:((x>eps)?1:0);
    }
    inline bool x_comp(CP &a,CP &b){
    	return (Sign(a.x-b.x))?(a.x<b.x):(a.y<b.y);
    }
    inline DB Fabs(DB x){
    	return x*Sign(x);
    }
    inline DB Dot(CV &u,CV &v){
    	return u.x*v.x+u.y*v.y;
    }
    inline DB Cro(CV &u,CV &v){
    	return u.x*v.y-u.y*v.x;
    }
    inline DB Len(CV &u){
    	return sqrt(Dot(u,u));
    }
    Vector operator - (CV &u,CV &v){
    	return Vector(u.x-v.x,u.y-v.y);
    }
    Vector operator + (CV &u,CV &v){
    	return Vector(u.x+v.x,u.y+v.y);
    }
    Vector operator * (CV &u,DB k){
    	return Vector(u.x*k,u.y*k);
    }
    bool operator == (CP &u,CP &v){
    	return !(Sign(u.x-v.x)&&Sign(u.y-v.y)); 
    } 
    inline Point PointTurn(CP &u,DB theta){
    	return Point(u.x*cos(theta)+u.y*sin(theta),-u.x*sin(theta)+u.y*cos(theta));
    }
    inline Point PointTurn(CP &u,DB theta,CP &c){
    	return Point((u.x-c.x)*cos(theta)+(u.y-c.y)*sin(theta)+c.x,-(u.x-c.x)*sin(theta)+(u.y-c.y)*cos(theta)+c.y);
    }
    inline bool PointonSeg(CP &u,CP &a,CP &b){
    	return !Sign(Cro(u-a,u-b))&&(Dot(u-a,u-b)<=0);
    }
    inline bool DistoSeg(CP &u,CP &a,CP &b){
    	if(a==b)
    		return Len(u-a);
    	Vector au=u-a,bu=u-b,ab=b-a;
    	if(Sign(Dot(au,ab))<0)
    		return Len(au);
    	if(Sign(Dot(bu,ab))>0)
    		return Len(bu);
    	return Fabs(Cro(au,ab)/Len(ab));
    }
    inline bool PointonLine(CP &u,CP &a,CP &b){
    	return !Sign(Cro(u-a,u-b));
    }
    inline Point FootPoint(CP &u,CP &a,CP &b){
    	Vector au=u-a,bu=u-b,ab=a-b;
    	DB aulen=Dot(au,ab)/Len(ab),bulen=-1.0*Dot(bu,ab)/Len(ab);
    	return a+ab*(aulen/(aulen+bulen));
    }
    inline Point SymPoint(CP &u,CP &a,CP &b){
    	return u+(FootPoint(u,a,b)-u)*2;
    }
    inline Point CrossLL(CP &a,CP &b,CP &c,CP &d){
    	Vector ab=b-a,cd=d-c,ca=a-c;
    	return a+ab*(Cro(cd,ca)/Cro(ab,cd));
    }
    inline bool CrossLS(CP &a,CP &b,CP &c,CP &d){
    	return (PointonLine(CrossLL(a,b,c,d),c,d));
    }
    inline bool CrossSS(CP &a,CP &b,CP &c,CP &d){
    	DB ab_c=Cro(b-a,c-a),ab_d=Cro(b-a,d-a);
    	DB cd_a=Cro(d-c,a-c),cd_b=Cro(d-c,b-c);
    	return (Sign(ab_c)*Sign(ab_d)<0)&&(Sign(cd_a)*Sign(cd_b)<0);
    }
    inline DB PolyArea(Poly &P){
    	DB res=0;
    	for(int i=0;i<(int)P.size();++i){
    		res+=Cro(P[i],P[(i+1)%P.size()]);
    	}
    	return res/2.0;
    }
    inline void ConvexHull(Poly &P,Poly &ans){
    	int n=P.size();
    	std::sort(P.begin(),P.end(),x_comp);
    	ans.resize(0);
    	int siz=0;
    	for(int i=0;i<n;++i){
    		while(siz>1&&Sign(Cro(ans[siz-1]-ans[siz-2],P[i]-ans[siz-2]))<=0)
    			chosen[idx[siz]]=false,--siz,ans.pop_back();
    		ans.push_back(P[i]),chosen[idx[++siz]=i]=true;
    	}
    	for(int i=n-1,st=siz;i>=0;--i){
    		while(siz>st&&Sign(Cro(ans[siz-1]-ans[siz-2],P[i]-ans[siz-2]))<=0)
    			chosen[idx[siz]]=false,--siz,ans.pop_back();
    		ans.push_back(P[i]),chosen[idx[++siz]=i]=true;
    	}
    	ans.pop_back();
    	return;
    }
    inline DB PolyDiameter(Poly &P){
    	int n=P.size();
    	if(P.size()<2)
    		return 0;
    	if(P.size()==2)
    		return Len(P[0]-P[1]);
    	int now=2;
    	DB res=0;
    	P.push_back(P[0]);
    	for(int i=0;i<n;++i){
    		while(Sign(Cro(P[i+1]-P[i],P[now]-P[i])-Cro(P[i+1]-P[i],P[now+1]-P[i]))<0)
    			now=(now+1)%n;
    		res=std::max(res,std::max(Len(P[now]-P[i]),Len(P[i+1]-P[i])));
    	}
    	P.pop_back();
    	return res;
    }
    int n;
    Poly Po,Hull;
    inline DB MaxTriangle(Poly &P){
    	int n=P.size();
    	if(P.size()<=2)
    		return 0;
    	int now=2;
    	DB res=0;
    	P.push_back(P[0]);
    	for(int i=0;i<n;++i){
    		while(Sign(Cro(P[i+1]-P[i],P[now]-P[i])-Cro(P[i+1]-P[i],P[now+1]-P[i]))<0)
    			now=(now+1)%n;
    		res=std::max(res,Fabs(Cro(P[i+1]-P[i],P[now]-P[i])));
    	}
    	P.pop_back();
    	return res;
    }
    inline void Solve_3(Poly &P){
    	DB Big_Area=PolyArea(Hull);
    	DB res=0;
    	for(int i=0;i<(int)P.size();++i){
    		if(!chosen[i]){
    			Poly New;
    			for(int j=0;j<3;++j){
    				for(int k=0;k<3;++k){
    					if(k!=j)
    						New.push_back(Hull[j]);
    				}
    				New.push_back(P[i]);
    			}
    			res=std::max(res,Big_Area-PolyArea(New));
    		}
    	}
    	printf("%.3lf",res);
    	return;
    }
    int main(void){
    	Po.resize(n=read());
    	for(int i=0;i<n;++i)
    		scanf("%lf%lf",&Po[i].x,&Po[i].y);
    	ConvexHull(Po,Hull);
    	if(Hull.size()<3){
    		printf("0.000");
    		return 0;
    	}
    	if(Hull.size()==3){
    		Solve_3(Hull);
    		return 0;
    	}else{
    		int m=Hull.size();
    		DB ans=0;
    		for(int i=0;i<m;++i){
    			int pL=i,pR=i+2;
    			for(int j=i+2;j<m;++j){
    				while((pL+1)%m!=j&&Sign(Cro(Hull[pL]-Hull[i],Hull[j]-Hull[i])-Cro(Hull[(pL+1)%m]-Hull[i],Hull[j]-Hull[i]))<0){
    					pL=(pL+1)%m;
    				}
    				while((pR+1)%m!=i&&Sign(Cro(Hull[j]-Hull[i],Hull[pR]-Hull[i])-Cro(Hull[j]-Hull[i],Hull[(pR+1)%m]-Hull[i]))<0){
    					pR=(pR+1)%m;
    				}
    				ans=std::max(ans,Cro(Hull[j]-Hull[i],Hull[pR]-Hull[i])/2.0+Cro(Hull[pL]-Hull[i],Hull[j]-Hull[i])/2.0);
    			}
    		}
    		printf("%.3lf",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    C# 工厂
    sql server 数据库 数据DateTime 转mysql
    java 快捷工具,如何清理不需要的引用
    动态调用webservice 接口
    动态调用wcf接口服务
    下载图片出现问题
    jQuery Validation Engine 表单验证
    mvc5 知识点01
    mvc5 @RenderSection("scripts", required: false) 什么意思
    mvc5 _ViewStart.cshtml 模板页如何定义
  • 原文地址:https://www.cnblogs.com/liuzongxin/p/16050748.html
Copyright © 2020-2023  润新知