I. Rise of the Robots
题目大意:在一个以 ( 0 , 0 ) (0, 0) (0,0) 为圆心 R R R 为半径的圆桌上要举行一场比赛,一个圆形机器人自身半径为 r r r ,他有 n n n 步行动,起点未知,给出每一步的 ( d x , d y ) (d_x, d_y) (dx,dy) ,设机器人当前在 ( x , y ) (x, y) (x,y) ,则下一步行动走到的点为 ( x + d x , y + d y ) (x + d_x, y + d_y) (x+dx,y+dy) ,现在问将起点设在哪里可以保证这个机器人在行动的全程自身边界不会超过圆桌,题目保证有解。
解
题目看似好像得找一个最小圆去覆盖每一个圆,然而其实我们可以发现,将这个覆盖的圆半径缩小 r r r 就正好是这些点最小圆覆盖。我们可以先假设机器人行动的起点在 ( 0 , 0 ) (0,0) (0,0) ,然后求这 n + 1 n+1 n+1 个点最小圆覆盖,求出圆心坐标 ( x , y ) (x, y) (x,y) 。因为题目保证了有解,所以我们将这个圆平移到圆心为 ( 0 , 0 ) (0, 0) (0,0) 的位置肯定是最优的(如果这里都不满足条件就没有地方满足条件了),因为我们这里相当于把最小覆盖圆挪到了圆心位置,那么我们自然就要把所有点移动同样的距离,也就是将起点移动同样的距离,即最终的起点答案为 ( − x , − y ) (-x, -y) (−x,−y) 。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 2;
const double eps = 1e-11;
int n;
double R, r;
struct Dot {
double x;
double y;
}dot[N];
struct Cir {
Dot o;
double r;
}ans;
double dis(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
Cir getr(double x1, double y1, double x2, double y2, double x3, double y3) {//三个点求三角形圆心坐标和半径
Cir temp;
temp.o.x = ((y2-y1)*(y3*y3-y1*y1+x3*x3-x1*x1)-(y3-y1)*(y2*y2-y1*y1+x2*x2-x1*x1))/(2.0*((x3-x1)*(y2-y1)-(x2-x1)*(y3-y1)));
temp.o.y = ((x2-x1)*(x3*x3-x1*x1+y3*y3-y1*y1)-(x3-x1)*(x2*x2-x1*x1+y2*y2-y1*y1))/(2.0*((y3-y1)*(x2-x1)-(y2-y1)*(x3-x1)));
temp.r = dis(temp.o.x, temp.o.y, x1, y1);
return temp;
}
bool inCir(Dot t) {
double check = (t.x - ans.o.x) * (t.x - ans.o.x) + (t.y - ans.o.y) * (t.y - ans.o.y);
return (check < ans.r * ans.r || fabs(check - ans.r * ans.r) < eps);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
freopen("robots.in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%lf%lf", &n, &R, &r);
dot[0].x = 0, dot[0].y = 0;
for (int i = 1; i <= n; ++i) {
scanf("%lf%lf", &dot[i].x, &dot[i].y);
dot[i].x += dot[i - 1].x, dot[i].y += dot[i - 1].y;
}
random_shuffle(dot, dot + n + 1);
ans.o.x = dot[0].x, ans.o.y = dot[0].y, ans.r = 0;
for (int i = 1; i <= n; ++i) {
if (inCir(dot[i])) continue;
ans.o.x = dot[i].x, ans.o.y = dot[i].y, ans.r = 0;
for (int j = 0; j < i; ++j) {
if (inCir(dot[j])) continue;
ans.o.x = (dot[i].x + dot[j].x) / 2;
ans.o.y = (dot[i].y + dot[j].y) / 2;
ans.r = dis(dot[i].x, dot[i].y, dot[j].x, dot[j].y) / 2;
for (int k = 0; k < j; ++k) {
if (inCir(dot[k])) continue;
ans = getr(dot[i].x, dot[i].y, dot[j].x, dot[j].y, dot[k].x, dot[k].y);
}
}
}
printf("%.9f %.9f\n", 0-ans.o.x, 0-ans.o.y);
}
}
最小圆覆盖
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 2;
const double eps = 1e-11;
int n;
struct Dot {
double x;
double y;
}dot[N];
struct Cir {
Dot o;
double r;
}ans;
double dis(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
Cir getr(double x1, double y1, double x2, double y2, double x3, double y3) {//三个点求三角形圆心坐标和半径
Cir temp;
temp.o.x = ((y2-y1)*(y3*y3-y1*y1+x3*x3-x1*x1)-(y3-y1)*(y2*y2-y1*y1+x2*x2-x1*x1))/(2.0*((x3-x1)*(y2-y1)-(x2-x1)*(y3-y1)));
temp.o.y = ((x2-x1)*(x3*x3-x1*x1+y3*y3-y1*y1)-(x3-x1)*(x2*x2-x1*x1+y2*y2-y1*y1))/(2.0*((y3-y1)*(x2-x1)-(y2-y1)*(x3-x1)));
temp.r = dis(temp.o.x, temp.o.y, x1, y1);
return temp;
}
bool inCir(Dot t) {
double check = (t.x - ans.o.x) * (t.x - ans.o.x) + (t.y - ans.o.y) * (t.y - ans.o.y);
return (check < ans.r * ans.r || fabs(check - ans.r * ans.r) < eps);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%lf%lf", &dot[i].x, &dot[i].y);
}
random_shuffle(dot, dot + n);
ans.o.x = dot[0].x, ans.o.y = dot[0].y, ans.r = 0;
for (int i = 1; i < n; ++i) {
if (inCir(dot[i])) continue;
ans.o.x = dot[i].x, ans.o.y = dot[i].y, ans.r = 0;
for (int j = 0; j < i; ++j) {
if (inCir(dot[j])) continue;
ans.o.x = (dot[i].x + dot[j].x) / 2;
ans.o.y = (dot[i].y + dot[j].y) / 2;
ans.r = dis(dot[i].x, dot[i].y, dot[j].x, dot[j].y) / 2;
for (int k = 0; k < j; ++k) {
if (inCir(dot[k])) continue;
ans = getr(dot[i].x, dot[i].y, dot[j].x, dot[j].y, dot[k].x, dot[k].y);
}
}
}
printf("%.10f\n%.10f %.10f", ans.r, ans.o.x, ans.o.y);
}