HDU4573/2013年长沙赛区Throw the Stones

来源:互联网 发布:合肥软件项目经理 编辑:程序博客网 时间:2024/05/15 23:43

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 followingN 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 operatorcs 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))

 

原创粉丝点击