总览:
随机增量法
圆的表示:
(
(
圆
心
(
x
,
y
)
)
,
半
径
r
)
((圆心(x,y)),半径r)
((圆心(x,y)),半径r)
初始圆为
(
(
0
,
0
)
,
0
)
((0,0),0)
((0,0),0)、
枚举每一个点,找到一个圆,使
p
1
−
p
n
o
w
p_1-p_{now}
p1−pnow 在圆内
枚举每一个点
p
i
p_i
pi,如果
p
i
p_i
pi 不在当前圆内,假设它在圆上,将圆设为
(
(
x
i
,
y
i
)
,
0
)
((x_i,y_i),0)
((xi,yi),0)
再枚举每一个它之前的点
p
j
p_j
pj,如果
p
j
p_j
pj 不在当前圆内,假设它在圆上,将圆设为
(
(
p
i
,
p
j
的
中
点
)
,
d
i
s
(
p
i
,
p
j
)
/
2
)
((p_i,p_j的中点),dis(p_i,p_j)/2)
((pi,pj的中点),dis(pi,pj)/2)
再枚举每一个
p
j
p_j
pj 之前的点
p
k
p_k
pk,如果
p
k
p_k
pk 不在当前圆内,假设它在圆上,将圆设为
p
i
,
p
j
,
p
k
的
三
点
圆
p_i,p_j,p_k的三点圆
pi,pj,pk的三点圆
求三点圆:
就是找外心
找两条边的中垂线求交即可
为防被卡,开始先打乱点的顺序
T1 P1742 最小圆覆盖
思路:
板子题
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
typedef unsigned long long ull;
typedef unsigned int uint;
#define pb push_back
#define mp make_pair
namespace IO {
char buf_[1 << 21], *p1_ = buf_, *p2_ = buf_;
#define ch() \
(p1_ == p2_ && \
(p2_ = (p1_ = buf_) + fread(buf_, 1, 1 << 21, stdin), p1_ == p2_) \
? EOF \
: *p1_++)
inline int in() {
int s = 0, f = 1;
char x = getchar();
for (; x < '0' || x > '9'; x = getchar())
if (x == '-') f = -1;
for (; x >= '0' && x <= '9'; x = getchar()) s = (s * 10) + (x & 15);
return f == 1 ? s : -s;
}
char _buf[1 << 21];
int _p1 = -1;
inline void flush() {
fwrite(_buf, 1, _p1 + 1, stdout);
_p1 = -1;
}
inline void pc(char x) {
if (_p1 == (1 << 21) - 1) flush();
_buf[++_p1] = x;
}
inline void out(int x) {
char k[30];
int pos = 0;
if (!x) {
pc('0');
return;
}
if (x < 0) {
pc('-');
x = -x;
}
while (x) {
k[++pos] = (x % 10) | 48;
x /= 10;
}
for (int i = pos; i; i--) pc(k[i]);
return;
}
inline void out(string x) {
int len = x.size();
for (int i = 0; i < len; i++) pc(x[i]);
}
} // namespace IO
using namespace IO;
const int A = 3e5 + 5;
const double EPS = 1e-15;
int n;
inline int cp(double u, double v) {
if (fabs(u - v) < EPS) return 0;
return u > v ? 1 : -1;
}
struct Point {
double x, y;
Point(double u = 0, double v = 0) { x = u, y = v; }
inline friend Point operator+(Point u, Point v) {
return Point(u.x + v.x, u.y + v.y);
}
inline friend Point operator-(Point u, Point v) {
return Point(u.x - v.x, u.y - v.y);
}
inline friend Point operator*(Point u, double v) {
return Point(u.x * v, u.y * v);
}
inline friend Point operator/(Point u, double v) {
return Point(u.x / v, u.y / v);
}
inline friend double operator^(Point u, Point v) {
return u.x * v.y - u.y * v.x;
}
inline friend double operator&(Point u, Point v) {
return u.x * v.x + u.y * v.y;
}
inline friend bool operator==(Point u, Point v) {
return !cp(u.x, v.x) && !cp(u.y, v.y);
}
inline friend bool operator!=(Point u, Point v) { return !(u == v); }
} p[A];
struct Line {
Point x, y;
Line(Point u = 0, Point v = 0) { x = u, y = v; }
};
struct Circle {
Point x;
double r;
Circle(Point u = 0, double v = 0) { x = u, r = v; }
} mn;
inline double dis(Point u, Point v) {
return sqrt((u.x - v.x) * (u.x - v.x) + (u.y - v.y) * (u.y - v.y));
}
inline int check(Point u, Circle v) { return cp(dis(u, v.x), v.r) != 1; }
inline Point inter(Line u, Line v) {
double s1 = (v.x - u.x) ^ (v.y - u.x), s2 = (v.y - u.y) ^ (v.x - u.y);
return u.x + (u.y - u.x) * s1 / (s1 + s2);
}
inline Line find(Line u) {
Point a = (u.x + u.y) / 2;
return Line(a, Point(a.x + (u.y - u.x).y, a.y - (u.y - u.x).x));
}
inline Circle circle(Point u, Point v, Point w) {
Line a = find(Line(u, v)), b = find(Line(v, w));
Point c = inter(a, b);
return Circle(c, dis(u, c));
}
signed main() {
srand(time(0));
n = in();
for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
random_shuffle(p + 1, p + 1 + n);
mn = Circle(Point(0, 0), 0);
for (int i = 1; i <= n; i++)
if (!check(p[i], mn)) {
mn = Circle(p[i], 0);
for (int j = 1; j <= i - 1; j++)
if (!check(p[j], mn)) {
mn = Circle((p[i] + p[j]) / 2, dis(p[i], p[j]) / 2);
for (int k = 1; k <= j - 1; k++) {
if (!check(p[k], mn)) mn = circle(p[i], p[j], p[k]);
}
}
}
printf("%0.10lf\n%0.10lf %0.10lf\n", mn.r, mn.x.x, mn.x.y);
flush();
return 0;
}
T2 P4288 [SHOI2014]信号增幅仪
思路:
先旋转坐标轴,将椭圆转正,然后放缩,将椭圆变成圆
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
typedef unsigned long long ull;
typedef unsigned int uint;
#define pb push_back
#define mp make_pair
namespace IO {
char buf_[1 << 21], *p1_ = buf_, *p2_ = buf_;
#define ch() \
(p1_ == p2_ && \
(p2_ = (p1_ = buf_) + fread(buf_, 1, 1 << 21, stdin), p1_ == p2_) \
? EOF \
: *p1_++)
inline int in() {
int s = 0, f = 1;
char x = ch();
for (; x < '0' || x > '9'; x = ch())
if (x == '-') f = -1;
for (; x >= '0' && x <= '9'; x = ch()) s = (s * 10) + (x & 15);
return f == 1 ? s : -s;
}
char _buf[1 << 21];
int _p1 = -1;
inline void flush() {
fwrite(_buf, 1, _p1 + 1, stdout);
_p1 = -1;
}
inline void pc(char x) {
if (_p1 == (1 << 21) - 1) flush();
_buf[++_p1] = x;
}
inline void out(int x) {
char k[30];
int pos = 0;
if (!x) {
pc('0');
return;
}
if (x < 0) {
pc('-');
x = -x;
}
while (x) {
k[++pos] = (x % 10) | 48;
x /= 10;
}
for (int i = pos; i; i--) pc(k[i]);
return;
}
inline void out(string x) {
int len = x.size();
for (int i = 0; i < len; i++) pc(x[i]);
}
} // namespace IO
using namespace IO;
const int A = 3e5 + 5;
const double EPS = 1e-7;
const double pi = acos(-1);
int n;
inline int cp(double u, double v) {
if (fabs(u - v) < EPS) return 0;
return u > v ? 1 : -1;
}
struct Point {
double x, y;
Point(double u = 0, double v = 0) { x = u, y = v; }
inline friend Point operator+(Point u, Point v) {
return Point(u.x + v.x, u.y + v.y);
}
inline friend Point operator-(Point u, Point v) {
return Point(u.x - v.x, u.y - v.y);
}
inline friend Point operator*(Point u, double v) {
return Point(u.x * v, u.y * v);
}
inline friend Point operator/(Point u, double v) {
return Point(u.x / v, u.y / v);
}
inline friend double operator^(Point u, Point v) {
return u.x * v.y - u.y * v.x;
}
inline friend double operator&(Point u, Point v) {
return u.x * v.x + u.y * v.y;
}
inline friend bool operator==(Point u, Point v) {
return !cp(u.x, v.x) && !cp(u.y, v.y);
}
inline friend bool operator!=(Point u, Point v) { return !(u == v); }
} p[A];
struct Line {
Point x, y;
Line(Point u = 0, Point v = 0) { x = u, y = v; }
};
struct Circle {
Point x;
double r;
Circle(Point u = 0, double v = 0) { x = u, r = v; }
} mn;
inline double dis(Point u, Point v) {
return sqrt((u.x - v.x) * (u.x - v.x) + (u.y - v.y) * (u.y - v.y));
}
inline int check(Point u, Circle v) { return cp(dis(u, v.x), v.r) != 1; }
inline Point inter(Line u, Line v) {
double s1 = (v.x - u.x) ^ (v.y - u.x), s2 = (v.y - u.y) ^ (v.x - u.y);
return u.x + (u.y - u.x) * s1 / (s1 + s2);
}
inline Line find(Line u) {
Point a = (u.x + u.y) / 2;
return Line(a, Point(a.x + (u.y - u.x).y, a.y - (u.y - u.x).x));
}
inline Circle circle(Point u, Point v, Point w) {
Line a = find(Line(u, v)), b = find(Line(v, w));
Point c = inter(a, b);
return Circle(c, dis(u, c));
}
inline Point rotate(Point u, double phi) {
return Point(cos(phi) * u.x - sin(phi) * u.y,
sin(phi) * u.x + cos(phi) * u.y);
}
signed main() {
srand(time(0));
n = in();
for (int i = 1; i <= n; i++) p[i].x = in(), p[i].y = in();
double phi = in();
phi = -pi * (phi / 180);
for (int i = 1; i <= n; i++) p[i] = rotate(p[i], phi);
int d = in();
for (int i = 1; i <= n; i++) p[i].x = p[i].x / d;
random_shuffle(p + 1, p + 1 + n);
mn = Circle(Point(0, 0), 0);
for (int i = 1; i <= n; i++)
if (!check(p[i], mn)) {
mn = Circle(p[i], 0);
for (int j = 1; j <= i - 1; j++)
if (!check(p[j], mn)) {
mn = Circle((p[i] + p[j]) / 2, dis(p[i], p[j]) / 2);
for (int k = 1; k <= j - 1; k++) {
if (!check(p[k], mn)) mn = circle(p[i], p[j], p[k]);
}
}
}
printf("%0.3lf\n", mn.r);
flush();
return 0;
}