hdu 6219

来源:互联网 发布:网络凶杀2视频 编辑:程序博客网 时间:2024/06/18 07:53

(计算几何 + DP)
题意:共有T(T<100)组测试数据,每个测试数据包含平面上n(n<50)个点的坐标,求它们能组成的最大空凸包的面积。(即这个凸包内部不包含任何其它的点)

思路:枚举凸包的左下角点,然后DP找出以这个点为起始位置能构成的最大空凸包面积,最后取这些空凸包面积的最大值为答案。DP过程:假设当前点O为左下角,dp[i][j]表示得是以Oiij为凸包的最后两条边所构成的凸包面积的最大值。状态转移方程:dp[i][j]=max(dp[i][j],triangle(O,i,j)+dp[j][k])。时间复杂度:O(n4)

吐槽:这个题关键是要想好怎么开始枚举!然后,嗯我知道这个题有O(n3)解法的,但是我并不会。。(不过这个4次方解法跑得速度还可以233)写代码的时候要尤其注意点在凸包边上的情况。最后想说代码里全部用int比全部用double跑起来速度快了好几倍。使用double的代码跑了1216ms,使用int的代码只跑了171ms。

代码:

#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#define LL long longusing namespace std;const int maxn = 60;struct Point {    int x, y;    Point(const Point& rhs): x(rhs.x), y(rhs.y){ }    Point(int x = 0, int y = 0): x(x), y(y) { }    friend Point operator + (const Point& A, const Point& B) { return Point(A.x+B.x, A.y+B.y); }    friend Point operator - (const Point& A, const Point& B) { return Point(A.x-B.x, A.y-B.y); }    friend bool operator == (const Point& A, const Point& B) { return A.x==B.x && A.y==B.y; }}P[maxn], Pcur[maxn];typedef Point Vector;int len2(Point A, Point B) { Point C = B-A; return (C.x*C.x + C.y*C.y); }int Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }bool cmp1(const Point& A, const Point& B) {    return A.y < B.y || (A.y == B.y && A.x < B.x);}bool cmp2(const Point& A, const Point& B) {    int c = Cross(A, B);    if(c == 0) return len2(A,Point(0,0)) < len2(B,Point(0,0));    return c > 0;}struct Line {    Point P;    Vector v;    Line() {}    Line(const Point& P, const Vector& v): P(P), v(v) {}};bool OnLeft(Line L, Point p) {    return Cross(L.v, p-L.P) > 0;}bool PointInTriangle(Point a, Point b, Point c, Point k) {    Line lx(a, b-a), ly(b, c-b), lz(c, a-c);    return OnLeft(lx, k) && OnLeft(ly, k) && OnLeft(lz, k);}int dp[maxn][maxn];int do_DP(int n) {    for(int i=0; i<n; i++) // initialize        for(int j=0; j<n; j++)            dp[i][j] = -1;    int ret = -1;  // work    for(int i=1; i<n; i++)        for(int j=1; j<i; j++) if(Cross(Pcur[i], Pcur[j]) != 0) {            bool triangle = 1; // see if 0,i,j can form a triangle            for(int k=j+1; k<i; k++)                if(PointInTriangle(Pcur[0], Pcur[j], Pcur[i], Pcur[k])) {                    triangle = 0; break ;                }            if(!triangle) continue ;            int tri_area = abs(Cross(Pcur[i]-Pcur[0], Pcur[j]-Pcur[0]));            dp[i][j] = tri_area; // start DP            if(Cross(Pcur[j], Pcur[j-1]) != 0) {                for(int k=1; k<j; k++)                    if(dp[j][k] > 0 && OnLeft(Line(Pcur[k], Pcur[j]-Pcur[k]), Pcur[i])) {                        dp[i][j] = max(dp[i][j], tri_area+dp[j][k]);                    }            }            ret = max(dp[i][j], ret);        }    return ret;};int solve(int n) {    sort(P, P+n, cmp1);    int ret = 0;    for(int i=0; i<n-2; i++) { // choose the lower left point for convex hull        for(int j=0; j+i<n; j++)            Pcur[j] = P[j+i] - P[i];        sort(Pcur+1, Pcur+n-i, cmp2);        ret = max(ret, do_DP(n-i));    }    return ret;}int main() {    //freopen("in.txt","r",stdin);    int T, n;    scanf("%d",&T);    while(T --) {        scanf("%d",&n);        for(int i=0; i<n; i++)            scanf("%d%d",&P[i].x,&P[i].y);        double ans = (double)solve(n)/2.0;        printf("%.1f\n",ans);    }    return 0;}
原创粉丝点击