HDU 4573 Throw the Stones(动态三维凸包)(2013 ACM-ICPC长沙赛区全国邀请赛)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4573

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 (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 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.
 
题目大意:给一个三维空间点集依次加入N个点,形成一个三维凸包。问加入哪一个点的时候,凸包的体积增量最大,即前 i 个点组成的凸包体积减去前 i - 1个点组成的凸包体积最大。输出这个点,并输出这个增量。
思路:http://blog.csdn.net/catalyst1314/article/details/9017673
PS:我的代码框架几乎都是照着上面写的。但是怎么看内存都会超出限制,虽然不知道为什么实际上没有(我算错了?),虽说现场没有这种限制。然后不知为何说时间复杂度是O(n*sqrt(n)),我怎么觉得最坏情况下还是O(n^2)的……
 
代码(531MS):
  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <cmath>
  6 using namespace std;
  7 typedef long long LL;
  8 
  9 const int MAXN = 10001;
 10 const double EPS = 1e-9;
 11 
 12 inline int sgn(double x) {
 13     return (x > EPS) - (x < -EPS);
 14 }
 15 
 16 struct Point {
 17     double x, y, z;
 18     Point() {}
 19     Point(double x, double y, double z): x(x), y(y), z(z) {}
 20     void read() {
 21         scanf("%lf%lf%lf", &x, &y, &z);
 22     }
 23     Point operator - (const Point &rhs) const {
 24         return Point(x - rhs.x, y - rhs.y, z - rhs.z);
 25     }
 26     double operator * (const Point &rhs) const {
 27         return x * rhs.x + y * rhs.y + z * rhs.z;
 28     }
 29 };
 30 double length(const Point &a) {
 31     return sqrt(a * a);
 32 }
 33 Point cross(const Point &a, const Point &b) {
 34     Point res;
 35     res.x = a.y * b.z - a.z * b.y;
 36     res.y = a.z * b.x - a.x * b.z;
 37     res.z = a.x * b.y - a.y * b.x;
 38     return res;
 39 }
 40 Point cross(const Point &o, const Point &a, const Point &b) {
 41     return cross(a - o, b - o);
 42 }
 43 double volume(const Point &a, const Point &b, const Point &c, const Point &d) {
 44     return cross(c - a , b - a) * (d - a) / 6;
 45 }
 46 Point p[MAXN];
 47 
 48 struct Face {
 49     int a, b, c;
 50     bool flag;
 51     Face() {}
 52     Face(int a, int b, int c, bool flag): a(a), b(b), c(c), flag(flag) {}
 53     bool can_see(const Point &q) {
 54         return sgn(volume(p[a], p[b], p[c], q)) > 0;
 55     }
 56 };
 57 Face fac[MAXN * 10];
 58 
 59 struct Convex {
 60     double diff_vol;
 61     int cnt, mat[MAXN][MAXN];
 62 
 63     void init() {
 64         cnt = 0;
 65         for(int i = 0; i < 4; ++i) {
 66             Face newf = Face((i + 1) % 4, (i + 2) % 4, (i + 3) % 4, true);
 67             if(newf.can_see(p[i])) swap(newf.a, newf.c);
 68             mat[newf.a][newf.b] = mat[newf.b][newf.c] = mat[newf.c][newf.a] = cnt;
 69             fac[cnt++] = newf;
 70         }
 71     }
 72 
 73     void restore(int k, int a, int b) {
 74         int f = mat[a][b];
 75         if(fac[f].flag) {
 76             if(fac[f].can_see(p[k])) dfs(k, f);
 77             else {
 78                 mat[b][a] = mat[a][k] = mat[k][b] = cnt;
 79                 fac[cnt++] = Face(b, a, k, true);
 80             }
 81         }
 82     }
 83 
 84     void dfs(int k, int f) {
 85         diff_vol += volume(p[fac[f].a], p[fac[f].b], p[fac[f].c], p[k]);
 86         fac[f].flag = false;
 87         restore(k, fac[f].b, fac[f].a);
 88         restore(k, fac[f].c, fac[f].b);
 89         restore(k, fac[f].a, fac[f].c);
 90     }
 91 
 92     double update(int k) {
 93         diff_vol = 0;
 94         for(int i = 0; i < cnt; ++i) {
 95             if(!fac[i].flag || !fac[i].can_see(p[k])) continue;
 96             dfs(k, i);
 97             break;
 98         }
 99         return diff_vol;
100     }
101 
102     double vol() {
103         double res = 0;
104         for(int i = 0; i < cnt; ++i) if(fac[i].flag)
105             res -= volume(p[fac[i].a], p[fac[i].b], p[fac[i].c], Point(0, 0, 0));
106         return res;
107     }
108 } solver;
109 
110 int n, kase;
111 
112 void solve() {
113     int king = 0;
114     double maxans = 0;
115     for(int i = 1, tmp = 1; i < n; ++i) {
116         if(tmp == 1) {
117             tmp += sgn(length(p[0] - p[i]));
118             if(tmp > 1) swap(p[1], p[i]);
119         } else if(tmp == 2) {
120             tmp += sgn(length(cross(p[0], p[1], p[i])));
121             if(tmp > 2) swap(p[2], p[i]);
122         } else if(tmp == 3) {
123             tmp += (sgn(volume(p[0], p[1], p[2], p[i])) != 0);
124             if(tmp > 3) {
125                 swap(p[3], p[i]);
126                 solver.init();
127                 for(int j = 4; j <= i; ++j) solver.update(j);
128                 king = i, maxans = solver.vol();
129             }
130         } else {
131             double v = solver.update(i);
132             if(sgn(v - maxans) > 0) {
133                 maxans = v;
134                 king = i;
135             }
136         }
137     }
138     printf("%d %.2f\n", king + 1, maxans);
139 }
140 
141 int main() {
142     while(scanf("%d", &n) != EOF) {
143         for(int i = 0; i < n; ++i) p[i].read();
144         printf("Case #%d:\n", ++kase);
145         solve();
146     }
147 }
View Code

 

posted @ 2014-08-14 12:32  Oyking  阅读(495)  评论(0编辑  收藏  举报