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\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/FrankChen831X/p/12366674.html

时间: 2024-10-12 02:21:32

O(n^3)求最大空凸包模板(2017沈阳icpc-C Empty Convex Polygons )的相关文章

HDU6219/POJ1259 [ICPC2017沈阳]Empty Convex Polygons 最大空凸包

Empty Convex Polygons Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 538    Accepted Submission(s): 138 Problem Description Given a set of distinct points S on a plane, we define a convex ho

最大空凸包模板

inline double sgn(double x, double y) { return fabs(x-y)<eps; } inline int sgn(int x, int y) { return x==y; } struct point { double x,y; }; double cross(point a, point b, point o) { return (a.x-o.x)*(o.y-b.y)-(a.y-o.y)*(o.x-b.x); } double dist(point

Game of Taking Stones &amp;&amp; POJ1259 /// 最大空凸包 几何+DP

题目大意: 给定n个点 求出这n个点中最大空凸包的面积 只放个模板 一份模板过两题(滑稽 这个讲解够详细了 https://blog.csdn.net/nyroro/article/details/45268767 #include <stdio.h> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const double eps=1e-8; dou

hdu4266(三维凸包模板题)

/*给出三维空间中的n个顶点,求解由这n个顶点构成的凸包表面的多边形个数. 增量法求解:首先任选4个点形成的一个四面体,然后每次新加一个点,分两种情况: 1> 在凸包内,则可以跳过 2> 在凸包外,找到从这个点可以"看见"的面,删除这些面, 然后对于一边没有面的线段,和新加的这个点新建一个面,至于这个点可以看见的面, 就是求出这个面的方程(可以直接求法向量). */ #include<iostream> #include<cmath> #includ

凸包模板 POJ1873

1 // 凸包模板 POJ1873 2 // n=15所以可以按位枚举求凸包,再记录数据 3 4 #include <iostream> 5 #include <cstdio> 6 #include <cstdlib> 7 #include <algorithm> 8 #include <vector> 9 #include <math.h> 10 using namespace std; 11 #define LL long lon

POJ 1113 凸包模板题

上模板. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <vector> #include <utility> #include <stack> #include <queue> #include <map> #include

POJ 3528 hdu 3662 三维凸包模板题

POJ 3528题:http://poj.org/problem?id=3528 HDU 3662:http://acm.hdu.edu.cn/showproblem.php?pid=3662 一个是求三维凸包面数,一个是求三维凸包表面积,都是很裸的. 贴代码: #include<stdio.h> #include<algorithm> #include<string.h> #include<math.h> #include<stdlib.h>

POJ - 1113 Wall (凸包模板题)

原题链接 模板题,直接说思路. 思路: 要求一距离凸包为 L 的图形的周长,即为 凸包周长+L为半径的圆周长 ,直接用 Graham 求一次凸包即可. 1 /* 2 * @Author: windystreet 3 * @Date: 2018-08-02 20:41:25 4 * @Last Modified by: windystreet 5 * @Last Modified time: 2018-08-02 22:30:59 6 */ 7 #include <stdio.h> 8 #inc

三维凸包模板

poj3528 参照 #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; #define inf 0x7fffffff #define max(a,b) (a>b?a:b) #define min(a,b) (a<b?a:b) #define eps 1e-7 #define MAXV 505 //三维点 s