import
java.util.ArrayList;
import
java.util.Collections;
import
java.util.List;
class
Point {
double
X, Y;
Point(
double
x,
double
y) {
X = x;
Y = y;
}
}
class
Circle {
Point C;
double
R;
Circle(Point center,
double
radius) {
C = center;
R = radius;
}
}
public
class
MinimumEnclosingCircle {
private
static
final
double
INF = 1e18;
private
static
double
dist(Point a, Point b) {
return
Math.sqrt(Math.pow(a.X - b.X,
2
) + Math.pow(a.Y - b.Y,
2
));
}
private
static
boolean
isInside(Circle c, Point p) {
return
dist(c.C, p) <= c.R;
}
private
static
Point getCircleCenter(
double
bx,
double
by,
double
cx,
double
cy) {
double
B = bx * bx + by * by;
double
C = cx * cx + cy * cy;
double
D = bx * cy - by * cx;
return
new
Point((cy * B - by * C) / (
2
* D), (bx * C - cx * B) / (
2
* D));
}
private
static
Circle circleFrom(Point A, Point B, Point C) {
Point I = getCircleCenter(B.X - A.X, B.Y - A.Y, C.X - A.X, C.Y - A.Y);
I.X += A.X;
I.Y += A.Y;
return
new
Circle(I, dist(I, A));
}
private
static
Circle circleFrom(Point A, Point B) {
Point C =
new
Point((A.X + B.X) /
2.0
, (A.Y + B.Y) /
2.0
);
return
new
Circle(C, dist(A, B) /
2.0
);
}
private
static
boolean
isValidCircle(Circle c, List<Point> P) {
for
(Point p : P) {
if
(!isInside(c, p)) {
return
false
;
}
}
return
true
;
}
private
static
Circle minCircleTrivial(List<Point> P) {
assert
P.size() <=
3
;
if
(P.isEmpty()) {
return
new
Circle(
new
Point(
0
,
0
),
0
);
}
else
if
(P.size() ==
1
) {
return
new
Circle(P.get(
0
),
0
);
}
else
if
(P.size() ==
2
) {
return
circleFrom(P.get(
0
), P.get(
1
));
}
for
(
int
i =
0
; i <
3
; i++) {
for
(
int
j = i +
1
; j <
3
; j++) {
Circle c = circleFrom(P.get(i), P.get(j));
if
(isValidCircle(c, P)) {
return
c;
}
}
}
return
circleFrom(P.get(
0
), P.get(
1
), P.get(
2
));
}
private
static
Circle welzlHelper(List<Point> P, List<Point> R,
int
n) {
if
(n ==
0
|| R.size() ==
3
) {
return
minCircleTrivial(R);
}
int
idx = (
int
) (Math.random() * n);
Point p = P.get(idx);
Collections.swap(P, idx, n -
1
);
Circle d = welzlHelper(P, R, n -
1
);
if
(isInside(d, p)) {
return
d;
}
R.add(p);
return
welzlHelper(P, R, n -
1
);
}
private
static
Circle welzl(List<Point> P) {
List<Point> PCopy =
new
ArrayList<>(P);
Collections.shuffle(PCopy);
return
welzlHelper(PCopy,
new
ArrayList<>(), PCopy.size());
}
public
static
void
main(String[] args) {
Circle mec = welzl(List.of(
new
Point(
0
,
0
),
new
Point(
0
,
1
),
new
Point(
1
,
0
)));
System.out.printf(
"Center = { %.5f, %.5f } Radius = %.6f\n"
,
mec.C.X, mec.C.Y, mec.R);
Circle mec2 = welzl(List.of(
new
Point(
5
, -
2
),
new
Point(-
3
, -
2
),
new
Point(-
2
,
5
),
new
Point(
1
,
6
),
new
Point(
0
,
2
)));
System.out.println(
"Center = { "
+ mec2.C.X +
", "
+
mec2.C.Y +
" } Radius = "
+ (
int
) Math.round(mec2.R));
}
}