4 public class asteroids_mb
implements Runnable
{
5 private static final double EPSILON
= 1e-6;
10 public final double z
;
12 public Point3d(double x
, double y
, double z
) {
18 public static Point3d
read(Scanner in
) {
19 final int x
= in
.nextInt();
20 final int y
= in
.nextInt();
21 final int z
= in
.nextInt();
22 return new Point3d(x
, y
, z
);
26 static class Plane3d
implements Comparable
<Plane3d
> {
32 public Plane3d(Point3d p1
, Point3d p2
, Point3d p3
) {
33 a
= (p2
.y
- p1
.y
) * (p3
.z
- p1
.z
) - (p3
.y
- p1
.y
) * (p2
.z
- p1
.z
);
34 b
= (p2
.z
- p1
.z
) * (p3
.x
- p1
.x
) - (p3
.z
- p1
.z
) * (p2
.x
- p1
.x
);
35 c
= (p2
.x
- p1
.x
) * (p3
.y
- p1
.y
) - (p3
.x
- p1
.x
) * (p2
.y
- p1
.y
);
36 d
= -(a
* p1
.x
+ b
* p1
.y
+ c
* p1
.z
);
37 final double norm
= Math
.sqrt(a
* a
+ b
* b
+ c
* c
);
43 if (a
< 0 || Math
.abs(a
) < EPSILON
&& b
< 0 || Math
.abs(a
) < EPSILON
&& Math
.abs(b
) < EPSILON
&& c
< 0) {
51 public double getDist(Point3d origin
) {
52 return a
* origin
.x
+ b
* origin
.y
+ c
* origin
.z
+ d
;
55 public int compareTo(Plane3d o
) {
56 if (a
< o
.a
- EPSILON
) {
59 if (a
> o
.a
+ EPSILON
) {
62 if (b
< o
.b
- EPSILON
) {
65 if (b
> o
.b
+ EPSILON
) {
68 if (c
< o
.c
- EPSILON
) {
71 if (c
> o
.c
+ EPSILON
) {
74 if (d
< o
.d
- EPSILON
) {
77 if (d
> o
.d
+ EPSILON
) {
85 public final Plane3d p
;
86 public final Point3d
[] v
;
88 public Face(Plane3d p
, Point3d
[] v
) {
94 static class Polyhedron
{
95 private final Point3d
[] vertices
;
97 public Polyhedron(Point3d
[] vertices
) {
98 this.vertices
= vertices
;
101 public static Polyhedron
read(Scanner in
) {
102 final int n
= in
.nextInt();
103 Point3d
[] vertices
= new Point3d
[n
];
104 for (int i
= 0; i
< n
; i
++) {
105 vertices
[i
] = Point3d
.read(in
);
107 return new Polyhedron(vertices
);
110 public double getDist() {
111 ArrayList
<Face
> faces
= new ArrayList
<Face
>();
112 TreeSet
<Plane3d
> facePlanes
= new TreeSet
<Plane3d
>();
113 for (int i
= 0; i
< vertices
.length
; i
++) {
114 Point3d v1
= vertices
[i
];
115 for (int j
= i
+ 1; j
< vertices
.length
; j
++) {
116 Point3d v2
= vertices
[j
];
117 for (int k
= j
+ 1; k
< vertices
.length
; k
++) {
118 Point3d v3
= vertices
[k
];
119 Plane3d p
= new Plane3d(v1
, v2
, v3
);
120 if (!facePlanes
.contains(p
)) {
121 final Face face
= buildFace(p
);
131 double dist
= Double
.MAX_VALUE
;
132 final Point3d centerOfMass
= getCenterOfMass(faces
);
133 for (Face f
: faces
) {
134 dist
= Math
.min(dist
, Math
.abs(f
.p
.getDist(centerOfMass
)));
139 private Point3d
getCenterOfMass(ArrayList
<Face
> faces
) {
144 final Point3d p1
= vertices
[0];
145 for (Face f
: faces
) {
147 for (int i
= 1; i
< f
.v
.length
- 1; i
++) {
149 Point3d p4
= f
.v
[i
+ 1];
150 final double thisVol
= getVolume(p1
, p2
, p3
, p4
);
151 final Point3d thisCentroid
= getCentroid(p1
, p2
, p3
, p4
);
153 x
+= thisVol
* thisCentroid
.x
;
154 y
+= thisVol
* thisCentroid
.y
;
155 z
+= thisVol
* thisCentroid
.z
;
158 return new Point3d(x
/ vol
, y
/ vol
, z
/ vol
);
161 private Point3d
getCentroid(Point3d p1
, Point3d p2
, Point3d p3
, Point3d p4
) {
163 (p1
.x
+ p2
.x
+ p3
.x
+ p4
.x
) / 4,
164 (p1
.y
+ p2
.y
+ p3
.y
+ p4
.y
) / 4,
165 (p1
.z
+ p2
.z
+ p3
.z
+ p4
.z
) / 4);
168 private double getVolume(Point3d p1
, Point3d p2
, Point3d p3
, Point3d p4
) {
169 final double dx1
= p2
.x
- p1
.x
;
170 final double dy1
= p2
.y
- p1
.y
;
171 final double dz1
= p2
.z
- p1
.z
;
172 final double dx2
= p3
.x
- p1
.x
;
173 final double dy2
= p3
.y
- p1
.y
;
174 final double dz2
= p3
.z
- p1
.z
;
175 final double dx3
= p4
.x
- p1
.x
;
176 final double dy3
= p4
.y
- p1
.y
;
177 final double dz3
= p4
.z
- p1
.z
;
179 (dx1
* (dy2
* dz3
- dz2
* dy3
) -
180 dy1
* (dx2
* dz3
- dz2
* dx3
) +
181 dz1
* (dx2
* dy3
- dy2
* dx3
))) / 6.0;
184 private Face
buildFace(Plane3d p
) {
185 final ArrayList
<Point3d
> verticesList
= new ArrayList
<Point3d
>();
186 boolean positive
= false;
187 boolean negative
= false;
188 for (int i
= 0; i
< vertices
.length
; i
++) {
189 final Point3d v
= vertices
[i
];
190 double dist
= p
.getDist(v
);
191 if (Math
.abs(dist
) > EPSILON
) {
197 if (positive
&& negative
) {
205 final Point3d
[] vertices
= new Point3d
[verticesList
.size()];
206 verticesList
.toArray(vertices
);
207 final AngleComparator angleComparator
= new AngleComparator(p
, vertices
[0]);
208 Arrays
.sort(vertices
, 1, vertices
.length
, angleComparator
);
209 return new Face(p
, vertices
);
213 static class AngleComparator
implements Comparator
<Point3d
> {
214 private final double nxx
;
215 private final double nxy
;
216 private final double nxz
;
217 private final double nyx
;
218 private final double nyy
;
219 private final double nyz
;
220 private final double x0
;
221 private final double y0
;
223 AngleComparator(Plane3d p
, Point3d origin
) {
224 if (Math
.abs(p
.a
) > EPSILON
|| Math
.abs(p
.b
) > EPSILON
) {
234 nyx
= nxy
* p
.c
- nxz
* p
.b
;
235 nyy
= nxz
* p
.a
- nxx
* p
.c
;
236 nyz
= nxx
* p
.b
- nxy
* p
.a
;
238 assert Math
.abs(p
.a
* nxx
+ p
.b
* nxy
+ p
.c
* nxz
) < EPSILON
;
239 assert Math
.abs(p
.a
* nyx
+ p
.b
* nyy
+ p
.c
* nyz
) < EPSILON
;
241 x0
= origin
.x
* nxx
+ origin
.y
* nxy
+ origin
.z
* nxz
;
242 y0
= origin
.x
* nyx
+ origin
.y
* nyy
+ origin
.z
* nyz
;
245 public int compare(Point3d o1
, Point3d o2
) {
246 final double x1
= o1
.x
* nxx
+ o1
.y
* nxy
+ o1
.z
* nxz
- x0
;
247 final double y1
= o1
.x
* nyx
+ o1
.y
* nyy
+ o1
.z
* nyz
- y0
;
248 final double x2
= o2
.x
* nxx
+ o2
.y
* nxy
+ o2
.z
* nxz
- x0
;
249 final double y2
= o2
.x
* nyx
+ o2
.y
* nyy
+ o2
.z
* nyz
- y0
;
250 final double prod
= x1
* y2
- x2
* y1
;
251 if (prod
< -EPSILON
) {
253 } else if (prod
> EPSILON
) {
261 public static void main(String
[] args
) {
262 new Thread(new asteroids_mb()).start();
267 final Scanner in
= new Scanner(new FileReader("asteroids.in"));
268 final PrintWriter out
= new PrintWriter("asteroids.out");
270 Polyhedron p1
= Polyhedron
.read(in
);
271 Polyhedron p2
= Polyhedron
.read(in
);
273 out
.println(p1
.getDist() + p2
.getDist());
277 } catch (IOException e
) {