uvalive 4589 Asteroids

题意:给两个凸包,凸包能旋转,求凸包重心之间的最短距离。

思路:显然两个凸包贴在一起时,距离最短。所以,先求重心,再求重心到各个面的最短距离。

三维凸包+重心求法

重心求法:在凸包内,任意枚举一点,在与凸包其他一个面组成一个三棱锥。求出每个三棱锥的重心,把三棱锥等效成一个个质点,再求整体的重心。

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<queue>
  6 using namespace std;
  7 
  8 const double eps = 1e-8;
  9 int dcmp(double x)
 10 {
 11     if(fabs(x) < eps) return 0;
 12     else return x < 0 ? -1 : 1;
 13 }
 14 
 15 struct Point3
 16 {
 17     double x, y, z;
 18     Point3(double x=0, double y=0, double z=0):x(x),y(y),z(z) { }
 19 };
 20 
 21 typedef Point3 Vector3;
 22 
 23 Vector3 operator + (const Vector3& A, const Vector3& B)
 24 {
 25     return Vector3(A.x+B.x, A.y+B.y, A.z+B.z);
 26 }
 27 Vector3 operator - (const Point3& A, const Point3& B)
 28 {
 29     return Vector3(A.x-B.x, A.y-B.y, A.z-B.z);
 30 }
 31 Vector3 operator * (const Vector3& A, double p)
 32 {
 33     return Vector3(A.x*p, A.y*p, A.z*p);
 34 }
 35 Vector3 operator / (const Vector3& A, double p)
 36 {
 37     return Vector3(A.x/p, A.y/p, A.z/p);
 38 }
 39 
 40 bool operator == (const Point3& a, const Point3& b)
 41 {
 42     return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0 && dcmp(a.z-b.z) == 0;
 43 }
 44 
 45 Point3 read_point3()
 46 {
 47     Point3 p;
 48     scanf("%lf%lf%lf", &p.x, &p.y, &p.z);
 49     return p;
 50 }
 51 
 52 double Dot(const Vector3& A, const Vector3& B)
 53 {
 54     return A.x*B.x + A.y*B.y + A.z*B.z;
 55 }
 56 double Length(const Vector3& A)
 57 {
 58     return sqrt(Dot(A, A));
 59 }
 60 double Angle(const Vector3& A, const Vector3& B)
 61 {
 62     return acos(Dot(A, B) / Length(A) / Length(B));
 63 }
 64 Vector3 Cross(const Vector3& A, const Vector3& B)
 65 {
 66     return Vector3(A.y*B.z - A.z*B.y, A.z*B.x - A.x*B.z, A.x*B.y - A.y*B.x);
 67 }
 68 double Area2(const Point3& A, const Point3& B, const Point3& C)
 69 {
 70     return Length(Cross(B-A, C-A));
 71 }
 72 double Volume6(const Point3& A, const Point3& B, const Point3& C, const Point3& D)
 73 {
 74     return Dot(D-A, Cross(B-A, C-A));
 75 }
 76 Point3 Centroid(const Point3& A, const Point3& B, const Point3& C, const Point3& D)
 77 {
 78     return (A + B + C + D)/4.0;
 79 }
 80 
 81 double rand01()
 82 {
 83     return rand() / (double)RAND_MAX;
 84 }
 85 double randeps()
 86 {
 87     return (rand01() - 0.5) * eps;
 88 }
 89 
 90 Point3 add_noise(const Point3& p)
 91 {
 92     return Point3(p.x + randeps(), p.y + randeps(), p.z + randeps());
 93 }
 94 
 95 struct Face
 96 {
 97     int v[3];
 98     Face(int a, int b, int c)
 99     {
100         v[0] = a;
101         v[1] = b;
102         v[2] = c;
103     }
104     Vector3 Normal(const vector<Point3>& P) const
105     {
106         return Cross(P[v[1]]-P[v[0]], P[v[2]]-P[v[0]]);
107     }
108     // f是否能看见P[i]
109     int CanSee(const vector<Point3>& P, int i) const
110     {
111         return Dot(P[i]-P[v[0]], Normal(P)) > 0;
112     }
113 };
114 
115 // 增量法求三维凸包
116 // 注意:没有考虑各种特殊情况(如四点共面)。实践中,请在调用前对输入点进行微小扰动
117 vector<Face> CH3D(const vector<Point3>& P)
118 {
119     int n = P.size();
120     vector<vector<int> > vis(n);
121     for(int i = 0; i < n; i++) vis[i].resize(n);
122 
123     vector<Face> cur;
124     cur.push_back(Face(0, 1, 2)); // 由于已经进行扰动,前三个点不共线
125     cur.push_back(Face(2, 1, 0));
126     for(int i = 3; i < n; i++)
127     {
128         vector<Face> next;
129         // 计算每条边的“左面”的可见性
130         for(int j = 0; j < cur.size(); j++)
131         {
132             Face& f = cur[j];
133             int res = f.CanSee(P, i);
134             if(!res) next.push_back(f);
135             for(int k = 0; k < 3; k++) vis[f.v[k]][f.v[(k+1)%3]] = res;
136         }
137         for(int j = 0; j < cur.size(); j++)
138             for(int k = 0; k < 3; k++)
139             {
140                 int a = cur[j].v[k], b = cur[j].v[(k+1)%3];
141                 if(vis[a][b] != vis[b][a] && vis[a][b]) // (a,b)是分界线,左边对P[i]可见
142                     next.push_back(Face(a, b, i));
143             }
144         cur = next;
145     }
146     return cur;
147 }
148 
149 struct ConvexPolyhedron
150 {
151     int n;
152     vector<Point3> P, P2;
153     vector<Face> faces;
154 
155     bool read()
156     {
157         if(scanf("%d", &n) != 1) return false;
158         P.resize(n);
159         P2.resize(n);
160         for(int i = 0; i < n; i++)
161         {
162             P[i] = read_point3();
163             P2[i] = add_noise(P[i]);
164         }
165         faces = CH3D(P2);
166         return true;
167     }
168 
169     Point3 centroid()
170     {
171         Point3 C = P[0];
172         double totv = 0;
173         Point3 tot(0,0,0);
174         for(int i = 0; i < faces.size(); i++)
175         {
176             Point3 p1 = P[faces[i].v[0]], p2 = P[faces[i].v[1]], p3 = P[faces[i].v[2]];
177             double v = -Volume6(p1, p2, p3, C);
178             totv += v;
179             tot = tot + Centroid(p1, p2, p3, C)*v;
180         }
181         return tot / totv;
182     }
183 
184     double mindist(Point3 C)
185     {
186         double ans = 1e30;
187         for(int i = 0; i < faces.size(); i++)
188         {
189             Point3 p1 = P[faces[i].v[0]], p2 = P[faces[i].v[1]], p3 = P[faces[i].v[2]];
190             ans = min(ans, fabs(-Volume6(p1, p2, p3, C) / Area2(p1, p2, p3)));
191         }
192         return ans;
193     }
194 };
195 
196 int main()
197 {
198     int n, m;
199     ConvexPolyhedron P1, P2;
200     while(P1.read() && P2.read())
201     {
202         Point3 C1 = P1.centroid();
203         double d1 = P1.mindist(C1);
204         Point3 C2 = P2.centroid();
205         double d2 = P2.mindist(C2);
206         printf("%.8lf
", d1+d2);
207     }
208     return 0;
209 }
View Code
原文地址:https://www.cnblogs.com/ITUPC/p/4903267.html