【bzoj1336/1337/2823】最小圆覆盖
题目描述:
给出平面上N个点,请求出一个半径最小的圆覆盖住所有的点
输入:
第一行给出数字N,现在N行,每行两个实数x,y表示其坐标.
输出:
输出最小半径,输出保留三位小数.
样例输入:
4
1 0
0 1
0 -1
-1 0
样例输出:
1.000
题解:
随机增量法大法好呀!!!看起来是O(n^3)的算法,实际上期望是O(n)的。
具体操作如下:
(1)把点的顺序打乱,
(2)一个一个点往里面加,如果当前的点不在当前的圆内,
(3)在当前圆内的点找到另一个点,然后以这两个点做圆,
(4)再判断剩下的点,如果还有不在这个圆内的,以当前的这三个点做圆。
代码也巨好写无比,简直跟暴力一样,但是就是跑得过!!!
(唯一的难点就是推三点外接圆的式子,我这个傻逼推了一整个晚上)
代码:(以bzoj1336为例)
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #ifdef WIN32 #define LL "%I64d" #else #define LL "%lld" #endif #ifdef CT #define debug(...) printf(__VA_ARGS__) #define setfile() #else #define debug(...) #define filename "" #define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout); #endif #define R register #define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++) #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b)) #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b)) #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0) #define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0) char B[1 << 15], *S = B, *T = B; inline int FastIn() { R char ch; R int cnt = 0; R bool minus = 0; while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ; ch == '-' ? minus = 1 : cnt = ch - '0'; while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0'; return minus ? -cnt : cnt; } inline double FastIn2() { R char ch = getc(); R double cnt = 0, ee = 1; R bool minus = 0, e = 0; while (ch != '-' && (ch < '0' || ch > '9')) ch = getc(); if (ch == '-') minus = 1, ch = getc(); while (ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0' , ch = getc(); if (ch == '.') e = 1, ee *= 0.1, ch = getc(); while (ch >= '0' && ch <= '9' && e) cnt += (ch - '0') * ee, ee *= 0.1, ch = getc(); return minus ? -cnt : cnt; } #define maxn 1000010 struct Point { double x, y; }p[maxn], o; Point cir(Point a, Point b, Point c) { R Point res; R double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1 * a1 + b1 * b1); R double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2 * a2 + b2 * b2); R double d = (a2 * b1 - a1 * b2) * 2; res.x = a.x + (c2 * b1 - c1 * b2) / d; res.y = a.y + (c1 * a2 - c2 * a1) / d; return res; } #define dist(_a, _b) (sqrt((_a.x - _b.x) * (_a.x - _b.x) + (_a.y - _b.y) * (_a.y - _b.y) ) ) int main() { // setfile(); R int n = FastIn(); for (R int i = 1; i <= n; ++i) p[i] = (Point) {FastIn2(), FastIn2()}; std::random_shuffle(p + 1, p + n + 1); o = p[1]; R double r = 0; for (R int i = 2; i <= n; ++i) if (dist(p[i], o) > r) { o = p[i]; r = 0; for (R int j = 1; j < i; ++j) if (dist(p[j], o) > r) { o.x = (p[i].x + p[j].x) / 2; o.y = (p[i].y + p[j].y) / 2; r = dist(p[i], o); for (R int k = 1; k < j; ++k) if (dist(p[k], o) > r) { o = cir(p[i], p[j], p[k]); r = dist(p[i], o); } } } printf("%.6f\n%.6f %.6f", r, o.x, o.y); return 0; }