zoukankan      html  css  js  c++  java
  • O(n^3)求最大空凸包模板(2017沈阳icpc-C Empty Convex Polygons )

    题目链接:https://vjudge.net/contest/358714#problem/C

    题意:求最大空凸包的面积,点的个数n<=50。

    思路:

      参考链接:https://blog.csdn.net/cdsszjj/article/details/79366813

      计算几何+DP。

      首先枚举凸包最左下角的点O,忽略O下面的点,对其它点进行极角排序。

      然后枚举凸包上的最后一个点i,用dp[i][j]表示以三角形Oij为凸包的最后一块三角形的最大空凸包的面积。那么可以得到转移方程:

      dp[i][j] = max ( dp[i][j] , S(Oij) + dp[j][k] ) (其中三角形Oij内无顶点,边Oi上无顶点,k点在ij的右边)

      (如果Oi上有顶点,Oi就只能是凸包的边,那么它不能更新dp[i][j],比如后面的dp[a][i]可以用S(Oai)+dp[i][j]来更新,此时Oi上的点就会成为凸包内部的点。所以此时只能用来更新ans,而不能更新dp数组。相反如果Oi上没有点,那么它可以更新ans和dp数组)

      

      上述的方法复杂度是O(n^4),而且没有说怎么遍历合法的j。

      后面讲怎么优化这个DP。

      对于每个i,令j1 = i-1。显然如果Oj1与Oi不共线的话这个j1将是第一个合法的j,如果共线的话,就找最大的不共线的作为j1,并且此时由于Oi上有点,不能将结果更新dp数组。

      显然第二个满足条件的j2就是最大的在ij1右边的点,j3就是最大的在ij2右边的点......

      这里我们用g[i][j] 表示 max ( dp[i][k] ) ,1<=k<=j。并且把jn作为凸包的最后一个点时,jn+1就是第一个符合条件的j,然后就可以在O(1)内更新dp[i][j]了:dp[i][j] = S(Oij) + g[j][k]。

      枚举O点为O(n),枚举i为O(n),枚举j为O(n),计算dp[i][j]为O(1),计算g是和枚举j并列的,为O(n)。因此总复杂度为O(n^3)。(另:代码中没有g数组,直接利用dp数组,因为得到dp数组之后就用不到了)

    AC代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    const int maxn=55;
    const double PI=acos(-1.0);
    
    struct Point{
        double x,y;
        Point():x(0),y(0){}
        Point(double x,double y):x(x),y(y){}
    }a[maxn],p[maxn],O;
    
    //计算叉积p0p1×p0p2
    double cross(Point p0,Point p1,Point p2){
        return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
    }
    //计算p1p2的距离
    double dis(Point p1,Point p2){
        return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
    }
    //极角排序函数,角度相同则距离小的在前面
    bool cmp(Point p1,Point p2){
        double tmp=cross(O,p1,p2);
        if(tmp>0) return true;
        else if(tmp==0&&dis(O,p1)<dis(O,p2)) return true;
        else return false;
    }
    
    int T,n,cnt;
    double ans,dp[maxn][maxn];
    
    void solve(){
        for(int i=0;i<n;++i)
            for(int j=0;j<n;++j)
                dp[i][j]=0.0;
        for(int i=1;i<=cnt;++i){
            int j=i-1;
            while(j&&!cross(O,p[i],p[j])) --j;
            int flag=(j==i-1);
            while(j){
                int k=j-1;
                while(k&&cross(p[i],p[j],p[k])>0) --k;
                double area=fabs(cross(O,p[i],p[j]))/2.0;
                if(k) area+=dp[j][k];
                if(flag) dp[i][j]=area;
                ans=max(ans,area);
                j=k;
            }
            if(flag) for(int j=1;j<i;++j) dp[i][j]=max(dp[i][j],dp[i][j-1]);
        }
    }
    
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            ans=0.0;
            for(int i=0;i<n;++i){
                int x,y;
                scanf("%d%d",&x,&y);
                a[i].x=x,a[i].y=y;
            }
            for(int i=0;i<n;++i){
                O=a[i];
                cnt=0;
                for(int j=0;j<n;++j)
                    if(a[j].y>a[i].y||a[j].y==a[i].y&&a[j].x>a[i].x) p[++cnt]=a[j];
                sort(p+1,p+cnt+1,cmp);
                solve();
            }
            printf("%.1f
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Lua/AHK socket tcp telnet
    Lua wait sleep
    Lua io.open read write seek flush setvbuf append
    stream file 文件 数据流
    AHK通讯 CMD Lua IPC
    零散 Lua/Excel/''/iup
    Windows Program File(x86) 路径 环境变量
    条件正则过滤筛选 V2
    条件正则过滤筛选 V1
    python导包出现的问题
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/12366674.html
Copyright © 2011-2022 走看看