HDU4573/2013年长沙赛区Throw the Stones

Description

Remember our childhood? A few nakedchildren throw stones standing on the same position, the one throws farther winthe game. Aha, of course, there are some naughty boys who care more aboutwhether they can urinate father.

You believe it or not, anyway, I believed.Nowadays, some of the children are smarter than we were, while others may bemore naughty.

A week ago, I saw several children throwstones. In fact, they are more clever than we were, since the game they played,apparently, is more complex than we did. Maybe you have different points ofview, however, you’d better learn about the rules of the game before expressingyour views. A group of children take turns to throw stones standing on the sameposition. After some child throw a stone, the children will draw a convexpolyhedron with smallest volume together to enclose all the stones thrown bythem. You may assume that the stone is so small as to be abstracted as a pointin three-dimensional space. Naively, the children regard the space enclosed bythe convex polyhedron as territory under their control. After a child throw hisstone, the score he obtains equals the incremental of the volume of theirterritory.     Unfortunately, the firstthree child’s score will always be zero. At last, the child with the highestscore will win the game, and known as the "King".

I think you have accepted my opinionalready, for the rules of their throwing stones game are really complicated.But, you also don’t need to be frustrated for it. Now, in order to show you aresmarter, maybe you can write a program to help the children point out their"King".

 

Input

Input consists of a number of cases. Thedata of each case appears on a number of input lines, the first of whichcontains an integerN. The following N lines contain threenumber (xi, yi,zi)indicating coordinates of the stone thrown by the i-th child.

Note: 1 <= N <= 10^4, 1 <= i <=N, -10^4 <= xi , yi, zi <= 10^4.

 

Output

For each test case, you should output twolines. The first line is "Case #K:", K means the number of the testcase. The second line is "i v", i means index of the "King"and v means the score of the "King". If there are more than one"King", output the one throws stone earlier than others.

Please round the result to 2 digits afterdecimal point if necessary.

 

Sample Input

4

1 0 0

1 1 0

0 1 0

0 0 1

5

1 0 0

1 1 0

0 1 0

0 0 0

0 0 1

 

Sample Output

Case #1

4 0.17

Case #2

5 0.33

最简单直接的方法是暴力计算三维凸包

时间复杂度为O(n^2),超时。

解题思路:

记录每个面的外法向量,类似邻接表的方式存储凸包记录相邻面信息。

对于新添加进来的一个石子(视作点光源),剔除当前凸包中的所有可见面,并更新维护凸包。

在删除和维护的过程中动态的更新凸包的体积,记录最大体积增量。

时间复杂度为O(n*sqrt(n))

 

特殊情况:

点的去重

所有点共线

所有点共面

精度

1e-8

1e-9

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

#define db double
#define rt return
#define cs const
#define cp const P&
#define op operator

cs db eps = 1e-9;

inline int sig(db x){rt (x>eps)-(x<-eps);}

cs int N = 10001;

struct P {
    db x, y, z;
    P(db a = 0, db b = 0, db c = 0):x(a),y(b),z(c){}
    void in(){scanf("%lf%lf%lf", &x, &y, &z);}
    P op+(cp a)cs{rt P(x+a.x, y+a.y, z+a.z);}
    P op-(cp a)cs{rt P(x-a.x, y-a.y, z-a.z);}
    P op*(cs db&k)cs{rt P(x*k, y*k, z*k);}
    P op^(cp a)cs{rt P(y*a.z-a.y*z, z*a.x-a.z*x, x*a.y-a.x*y);}
    db op*(cp a)cs{rt x*a.x + y*a.y + z*a.z;}
    P cross(P a, P b){rt a-*this ^ b-*this;}
    db dot(P a, P b){rt (a-*this) * (b-*this);}
    db L(){rt sqrt(x*x + y*y + z*z);}
    db V6(P b, P c){rt (b ^ c) * (*this);}
}p[N];

int n;

db diff_vol, max_diff;

struct convex {
    int cnt, blg[N][N];
    struct face {
       int a, b, c, is;
       face(int x=0,int y=0,int z=0,int w=0):a(x),b(y),c(z),is(w){}
       int visible(P me) {
           rt sig(p[a].cross(p[b],p[c]) * (me-p[a])) > 0;
       }
    }fac[N*10];
    int col(int a, int b, int c){rt p[a].cross(p[b],p[c]).L() < eps;}
    int cop(int a, int b, int c, int d){rt !sig(p[a].cross(p[b],p[c])*(p[d]-p[a]));}
    void deal(int k, int a, int b) {
       int f = blg[a][b];
       if(fac[f].is) {
           if(fac[f].visible(p[k])) dfs(k, f);
           else {
               diff_vol += p[b].V6(p[a], p[k]);
               face add = face(b, a, k, 1);
               blg[b][a] = blg[a][k] = blg[k][b] = cnt;
               fac[cnt++] = add;
           }
       }
    }
    void dfs(int k, int cur) {
       diff_vol -= p[fac[cur].a].V6(p[fac[cur].b], p[fac[cur].c]);
       fac[cur].is = 0;
       deal(k, fac[cur].b, fac[cur].a);
       deal(k, fac[cur].c, fac[cur].b);
       deal(k, fac[cur].a, fac[cur].c);
    }
    void init() {
        cnt = 0;
        for(int i = 0; i < 4; i++) {
           face add = face((i+1)%4, (i+2)%4, (i+3)%4, 1);
           if(add.visible(p[i])) swap(add.b, add.c);
           blg[add.a][add.b] = blg[add.b][add.c] = blg[add.c][add.a] = cnt;
           fac[cnt++] = add;
        }
    }
    void update(int k) {
        for(int i = 0; i < cnt; i++)
            if(fac[i].is && fac[i].visible(p[k])) {
                dfs(k, i); break;
            }
    }
    db volume() {
       db v = 0.;
       for(int i = 0; i < cnt; i++)
           v += fac[i].is * p[fac[i].a].V6(p[fac[i].b], p[fac[i].c]);
       rt v / 6.;
    }
}hull;

void solve(int number, int cas) {
    max_diff = 0.;
    int king = 1, tag = 1;
    p[0].in();
    for(int i = 1; i < number; i++) {
        p[i].in();
        if(tag == 1) {
            tag += sig((p[0]-p[i]).L());
            if(tag > 1) swap(p[1], p[i]);
            continue;
        }
        if(tag == 2) {
            tag += sig((p[0].cross(p[1], p[i])).L());
            if(tag > 2) swap(p[2], p[i]);
            continue;
        }
        if(tag == 3) {
            tag += sig(p[0].cross(p[1], p[2]) * (p[i]-p[0])) != 0;
            if(tag > 3) {
                swap(p[3], p[i]);
                hull.init();
                for(int j = 4; j <= i; j++) hull.update(j);
                king = i + 1, max_diff = hull.volume();
            }
            continue;
        }
        diff_vol = 0.;
        hull.update(i);
        diff_vol /= 6.;
        if(sig(diff_vol - max_diff) > 0) {
            max_diff = diff_vol;
            king = i + 1;
        }
    }
    printf("Case #%d:\n%d %.2lf\n", cas, king, max_diff);
}

int main() {
    
    int number, cas = 1;
    while(scanf("%d", &number) != -1) solve(number, cas++);
    rt 0;
}


度为O(n*sqrt(n))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值