hdu 3662 3D Convex Hull

Problem - 3662

  题意很简单,构造三维凸包,求凸包有多少个面。

代码如下:

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <cmath>
  6 
  7 using namespace std;
  8 
  9 const double EPS = 1e-10;
 10 const int N = 333;
 11 inline int sgn(double x) { return (x > EPS) - (x < -EPS);}
 12 struct Point {
 13     double x, y, z;
 14     Point() {}
 15     Point(double x, double y, double z) : x(x), y(y), z(z) {}
 16     bool operator < (Point a) const {
 17         if (sgn(x - a.x)) return x < a.x;
 18         if (sgn(y - a.y)) return y < a.y;
 19         return z < a.z;
 20     }
 21     bool operator == (Point a) const { return !sgn(x - a.x) && !sgn(y - a.y) && !sgn(z - a.z);}
 22     Point operator + (Point a) { return Point(x + a.x, y + a.y, z + a.z);}
 23     Point operator - (Point a) { return Point(x - a.x, y - a.y, z - a.z);}
 24     Point operator * (double p) { return Point(x * p, y * p, z * p);}
 25     Point operator / (double p) { return Point(x / p, y / p, z / p);}
 26 } ;
 27 inline double dot(Point a, Point b) { return a.x * b.x + a.y * b.y + a.z * b.z;}
 28 inline double dot(Point o, Point a, Point b) { return dot(a - o, b - o);}
 29 inline Point cross(Point a, Point b) { return Point(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);}
 30 inline Point cross(Point o, Point a, Point b) { return cross(a - o, b - o);}
 31 inline double veclen(Point x) { return sqrt(dot(x, x));}
 32 inline double area(Point o, Point a, Point b) { return veclen(cross(o, a, b)) / 2.0;}
 33 inline double volume(Point o, Point a, Point b, Point c) { return dot(cross(o, a, b), c - o) / 6.0;}
 34 
 35 struct _3DCH{
 36     Point pt[N];
 37     int pcnt;
 38     struct Face {
 39         int a, b, c;
 40         bool ok;
 41         Face() {}
 42         Face(int a, int b, int c) : a(a), b(b), c(c) { ok = true;}
 43     } fc[N << 2];
 44     int fcnt;
 45     int fid[N][N];
 46 
 47     bool outside(int p, int a, int b, int c) { return sgn(volume(pt[a], pt[b], pt[c], pt[p])) < 0;}
 48     bool outside(int p, int f) { return outside(p, fc[f].a, fc[f].b, fc[f].c);}
 49     void addface(int a, int b, int c, int d) {
 50         if (outside(d, a, b, c)) fc[fcnt] = Face(c, b, a), fid[c][b] = fid[b][a] = fid[a][c] = fcnt++;
 51         else fc[fcnt] = Face(a, b, c), fid[a][b] = fid[b][c] = fid[c][a] = fcnt++;
 52     }
 53 
 54     bool dfs(int p, int f) {
 55         if (!fc[f].ok) return true;
 56         int a = fc[f].a, b = fc[f].b, c = fc[f].c;
 57         if (outside(p, a, b, c)) {
 58             fc[f].ok = false;
 59             if (!dfs(p, fid[b][a])) addface(p, a, b, c);
 60             if (!dfs(p, fid[c][b])) addface(p, b, c, a);
 61             if (!dfs(p, fid[a][c])) addface(p, c, a, b);
 62             return true;
 63         }
 64         return false;
 65     }
 66     void build() {
 67         bool ok;
 68         fcnt = 0;
 69         sort(pt, pt + pcnt);
 70         pcnt = unique(pt, pt + pcnt) - pt;
 71         ok = false;
 72         for (int i = 2; i < pcnt; i++) {
 73             if (sgn(area(pt[0], pt[1], pt[i]))) {
 74                 ok = true;
 75                 swap(pt[i], pt[2]);
 76                 break;
 77             }
 78         }
 79         if (!ok) return ;
 80         ok = false;
 81         for (int i = 3; i < pcnt; i++) {
 82             if (sgn(volume(pt[0], pt[1], pt[2], pt[i]))) {
 83                 ok = true;
 84                 swap(pt[i], pt[3]);
 85                 break;
 86             }
 87         }
 88         if (!ok) return ;
 89         addface(0, 1, 2, 3);
 90         addface(1, 2, 3, 0);
 91         addface(2, 3, 0, 1);
 92         addface(3, 0, 1, 2);
 93         for (int i = 4; i < pcnt; i++) {
 94             for (int j = fcnt - 1; j >= 0; j--) {
 95                 if (outside(i, j)) {
 96                     dfs(i, j);
 97                     break;
 98                 }
 99             }
100         }
101         int sz = fcnt;
102         fcnt = 0;
103         for (int i = 0; i < sz; i++) if (fc[i].ok) fc[fcnt++] = fc[i];
104     }
105     double facearea() {
106         double ret = 0.0;
107         for (int i = 0; i < fcnt; i++) ret += area(pt[fc[i].a], pt[fc[i].b], pt[fc[i].c]);
108         return ret;
109     }
110     bool same(int i, int j) {
111         int a = fc[i].a, b = fc[i].b, c = fc[i].c;
112         if (sgn(volume(pt[a], pt[b], pt[c], pt[fc[j].a]))) return false;
113         if (sgn(volume(pt[a], pt[b], pt[c], pt[fc[j].b]))) return false;
114         if (sgn(volume(pt[a], pt[b], pt[c], pt[fc[j].c]))) return false;
115         return true;
116     }
117     int facecnt() {
118         int cnt = 0;
119         for (int i = 0; i < fcnt; i++) {
120             bool ok = true;
121             for (int j = 0; j < i; j++) {
122                 if (same(i, j)) {
123                     ok = false;
124                     break;
125                 }
126             }
127             if (ok) cnt++;
128         }
129         return cnt;
130     }
131 } ch;
132 
133 int main() {
134 //    freopen("in", "r", stdin);
135     int n;
136     double x, y, z;
137     while (~scanf("%d", &ch.pcnt)) {
138         for (int i = 0; i < ch.pcnt; i++) {
139             scanf("%lf%lf%lf", &x, &y, &z);
140             ch.pt[i] = Point(x, y, z);
141         }
142         ch.build();
143 //        printf("%.3f
", ch.facearea());
144         printf("%d
", ch.facecnt());
145     }
146     return 0;
147 }
View Code

  三维凸包还是挺简单的,不用抄模板也能敲出来。不过,还不熟练,敲了接近一个钟。

——written by Lyon

原文地址:https://www.cnblogs.com/LyonLys/p/hdu_3662_Lyon.html