Hdu 4573 Throw the Stones 2013长沙邀请赛

Throw the Stones

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 13    Accepted Submission(s): 2


Problem Description
  Remember our childhood? A few naked children throw stones standing on the same position, the one throws farther win the game. Aha, of course, there are some naughty boys who care more about whether 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 be more naughty.
  A week ago, I saw several children throw stones. 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 of view, however, you’d better learn about the rules of the game before expressing your views. A group of children take turns to throw stones standing on the same position. After some child throw a stone, the children will draw a convex polyhedron with smallest volume together to enclose all the stones thrown by them. You may assume that the stone is so small as to be abstracted as a point in three-dimensional space. Naively, the children regard the space enclosed by the convex polyhedron as territory under their control. After a child throw his stone, the score he obtains equals the incremental of the volume of their territory.   Unfortunately, the first three child’s score will always be zero. At last, the child with the highest score will win the game, and known as the "King".
  I think you have accepted my opinion already, 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 are smarter, maybe you can write a program to help the children point out their "King".
 

Input
  Input consists of a number of cases. The data of each case appears on a number of input lines, the first of which contains an integer N. The following N lines contain three number (x i, y i, z i) indicating coordinates of the stone thrown by the i-th child.  
Note: 1 <= N <= 10^4, 1 <= i <= N, -10^4 <= x i  , y i  , z i  <= 10^4.
 

Output
  For each test case, you should output two lines. The first line is "Case #K:", K means the number of the test case. 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 after decimal 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
 

Source
 

Recommend
zhoujiaqi2010
 

    题意较简单,略去。

    典型的三维计算几何问题。

   题目难度为偏难。

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

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

    解题思路:

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

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

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

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

 

 

#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() {
    //freopen("Throw_The_Stones.in", "r", stdin);
    //freopen("testThrow_The_Stones.out", "w", stdout);
    int number, cas = 1;
    while(scanf("%d", &number) != -1) solve(number, cas++);
    rt 0;
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值