zoukankan      html  css  js  c++  java
  • ●POJ 2079 Triangle

    题链:

    http://poj.org/problem?id=2079

    题解:

    计算几何,凸包,旋转卡壳

    复杂度O(N^2),(O(N)什么的就不说了,我觉得我看过的O(N)方法正确性都有问题,虽然有些AC了,那应该是鲁棒性太强了,谁叫他们非要每挪动一步都取MAX的呢)

    做法:

    (三角形的三个顶点在凸包的顶点上,同时显然三角形的底边不一定为凸包的边啦!)

    枚举i,j两点,使得有向线段$vec{ij}$作为三角形底边。

    然后在有向线段$vec{ij}$的右侧区域(凸包上),寻找k点使得三角形ijk面积最大,用叉积判断是第k个点优还是第k+1个点优。

    注意到单调性,k可以用旋转卡壳的思想枚举得到。 


    附一个简单的证明:三角形的顶点一定在凸包顶点上:

    假设现在取得一个三角形P1P2P3,且P1在凸包内。

    做过P1的直线l垂直于线段P2P3所在的直线。

    显然,把P1点沿着垂线l,向远离线段P2P3的方向移动会使得三角形面积增大。

    最后会移动到凸包的顶点上或者凸包的一条边上。

    若移到了顶点上,那就表明三角形的定点在凸包的顶点上最优。

    若在移到了凸包的一条边上,那也可以通过在边上移动直到达到一个顶点,这样也会使面积变大。

    综上,三角形的三个顶点一定在凸包的定点上。

    代码:

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 50050
    using namespace std;
    const double eps=1e-8;
    int sign(double x){
    	if(fabs(x)<=eps) return 0;
    	return x<0?-1:1;
    }
    struct Point{
    	double x,y;
    	Point(double _x=0,double _y=0):x(_x),y(_y){}
    	void Read(){scanf("%lf%lf",&x,&y);}
    };
    typedef Point Vector;
    bool operator < (Point A,Point B){return sign(A.x-B.x)<0||(sign(A.x-B.x)==0&&sign(A.y-B.y)<0);}
    bool operator == (Point A,Point B){return sign(A.x-B.x)==0&&sign(A.y-B.y)==0;}
    Vector operator - (Point A,Point B){return Vector(A.x-B.x,A.y-B.y);}
    double operator ^ (Vector A,Vector B){return A.x*B.y-A.y*B.x;}
    double operator * (Vector A,Vector B){return A.x*B.x+A.y*B.y;}
    Point D[MAXN],C[MAXN];
    int Andrew(int dnt){
    	int cnt=0,k;
    	sort(D+1,D+dnt+1);
    	dnt=unique(D+1,D+dnt+1)-D-1;
    	for(int i=1;i<=dnt;i++){
    		while(cnt>1&&sign((C[cnt]-C[cnt-1])^(D[i]-C[cnt-1]))<=0) cnt--;
    		C[++cnt]=D[i];
    	} k=cnt;
    	for(int i=dnt-1;i>=1;i--){
    		while(cnt>k&&sign((C[cnt]-C[cnt-1])^(D[i]-C[cnt-1]))<=0) cnt--;
    		C[++cnt]=D[i];
    	} if(dnt>1) cnt--;
    	return cnt;
    }
    double DA(Point P,Point P1,Point P2){//Directd_Area
    	return fabs((P1-P)^(P2-P));
    }
    double RC(int cnt){//Rotating_Calipers
    	double S=0;
    	if(cnt==1||cnt==2) return 0;
    	C[cnt+1]=C[1];
    	for(int i=1;i<=cnt;i++){
    		int k=i+1;
    		for(int cj=2,j;j=(i+cj-1)%cnt+1,cj<cnt;cj++){
    			while(sign(DA(C[i],C[j],C[k])-DA(C[i],C[j],C[k+1]))<=0) 
    				k=k%cnt+1;
    			S=max(S,DA(C[i],C[j],C[k]));
    		}
    	}
    	return S/2;
    }
    int main(){
    	int n; 
    	while(~scanf("%d",&n)&&n!=-1){
    		for(int i=1;i<=n;i++) D[i].Read();
    		printf("%.2lf
    ",RC(Andrew(n)));
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Editplus中添加System.out.println()快捷键
    API使用
    项目有两个红点
    no console to display at this time
    startup.bat闪退问题
    filter的dispatcher节点
    【DP专题】——洛谷P2467地精部落
    输入年月日,计算这是该年中第几天
    输出N以内的完整数
    python中关于EOF的tips
  • 原文地址:https://www.cnblogs.com/zj75211/p/8227660.html
Copyright © 2011-2022 走看看