Machining Disc Rotors Gym - 101955L(计算几何)
Machining Disc Rotors Gym - 101955L
题意:有一个圆心为\((0,0)\)的大圆被\(n\)个互不相交的圆切割(下图阴影部分为割掉的面积)。保证\(n\)个圆中不会有某个包含整个大圆的情况。问切割后大圆剩余部分的直径(多边形上两点最远距离)。
题解:显然剩余部分的直径是以下两种之一:
- 原本大圆的直径。
- 两个交点的距离。
如何判断是否存在直径呢?我们可以把每一个交点关于圆心作对称点,如果有一个对称点都不在\(n\)个圆内,说明这个点与对称点构成了一条没有被切掉的直径。若没有则是两交点之间的最大距离。
#include <bits/stdc++.h>
#define fopi freopen("in.txt", "r", stdin)
#define fopo freopen("out.txt", "w", stdout)
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const double eps = 1e-10;
const int maxn = 1000 + 10;
struct Point{
double x,y;
Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B){
return Vector(A.x+B.x,A.y+B.y);
}
Vector operator - (Point A,Point B){
return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (Point A,double p){
return Vector(A.x*p,A.y*p);
}
int dcmp(double x) { return fabs(x) < eps ? 0 : (x < 0 ? -1 : 1); }
bool operator == (const Point& a,const Point& b){
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double Dot(Vector A,Vector B){
return A.x*B.x+A.y*B.y;
}
double Length(Vector A){
return sqrt(Dot(A,A));
}
struct Circle{
Point c;
double r;
Circle() {}
Circle(Point c,double r):c(c),r(r){}
Point point(double a){
return Point(c.x+cos(a)*r,c.y+sin(a)*r);
}
};
double angle(Vector v) {
return atan2(v.y, v.x);
}
//Circle and Circle intersection
int CCIntersection(Circle C1,Circle C2,vector<Point>& sol){
double d=Length(C1.c-C2.c);
if(dcmp(d)==0){
if(dcmp(C1.r-C2.r)==0)return -1;
return 0;
}
if(dcmp(C1.r+C2.r-d)<0)return 0;
if(dcmp(fabs(C1.r-C2.r)-d)>0)return 0;
double a=angle(C2.c-C1.c);
double da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));
Point p1=C1.point(a-da),p2=C1.point(a+da);
sol.push_back(p1);
if(p1==p2)return 1;
sol.push_back(p2);
return 2;
}
bool PinC(Point p, Circle c) { //Point in Circle
double dist = Length(p-c.c);
return dcmp(dist-c.r) < 0;
}
int T, n;
double r;
Circle a[maxn];
vector<Point> sect, k;
bool check() {
if (sect.empty()) return true;
for (auto p : sect) {
bool flag = true;
Point p1 = {-p.x, -p.y};
for (int i = 1; i <= n; i++)
if (PinC(p1, a[i])) {
flag = false;
break;
}
if (flag) return true;
}
return false;
}
int main() {
scanf("%d", &T);
for (int ca = 1; ca <= T; ca++) {
sect.clear();
scanf("%d%lf", &n, &r);
Circle mid = {{0,0}, r};
Point p1, p2;
for (int i = 1; i <= n; i++) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
a[i] = {{x, y}, z};
CCIntersection(a[i], mid, sect);
}
double ans = 0, tmp;
for (int i = 0; i < sect.size(); i++)
for (int j = i+1; j < sect.size(); j++) {
if ((tmp = Length(sect[i]-sect[j])) > ans) ans = tmp;
}
printf("Case #%d: %.15f\n", ca, check() ? 2*r : ans);
}
}