Gym - 101955L Machining Disc Rotors 计算几何 圆剩余部分直径

本文探讨了一道编程题,通过计算几何的方法解决n个圆与一个中心圆相交后,求剩余部分的最大直径问题。介绍了如何判断剩余部分是否存在直径等于2*R,并提供了详细的代码实现。

题目链接:https://vjudge.net/problem/Gym-101955L

题意:n个圆和 圆(0,0,R) 部分相交,求剩余圆的直径

题解:如果剩余部分存在直径的话,那就是2*R,这个怎么判断呢,对于每一个交点,判断他关于(0,0)的对称点是不是在n个圆内,如果都不在的话,那就存在2*R的直径,如果都没有的话,那就是任意两个点的最大距离了

#include <bits/stdc++.h>
using namespace std;
const double PI = acos(-1);
const double eps = 1e-10;
int sgn(double x) {
	if(fabs(x) < eps) return 0;
	if(x < 0) return -1;
	return 1;
}
int n;
double R;
double sqr(double x) {
	return x * x;
}
struct Point{
	double x, y;
	Point(){
	}
	Point(double x_, double y_) {
		x = x_;
		y = y_;
	}
	bool operator == (Point b)const{
        return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
    }
    bool operator < (Point b)const{
        return sgn(x-b.x)== 0-sgn(y-b.y)?0:x<b.x;
    }
    Point operator-(const Point &b)const{
        return Point(x-b.x,y-b.y);
    }
    //2??y
    double operator ^(const Point &b)const{
        return x*b.y-y*b.x;
    }
    //μ??y
    double operator *(const Point &b)const{
        return x*b.x + y*b.y;
    }
     Point operator +(const Point &b)const{
        return Point(x+b.x,y+b.y);
    }
    Point operator *(const double &k)const{
        return Point(x*k,y*k);
    }
    Point operator /(const double &k)const{
        return Point(x/k,y/k);
    }
	double distance(Point p) {
		return sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
	}
	double len() {
		return sqrt(x * x + y * y);
	}
	Point trunc(double r) {
		double l = len();
		if(!sgn(l)) return *this;
		r /= l;
		return Point(x * r, y * r);
	}
	Point rotleft() {
		return Point(-y, x);
	}
	Point rotright() {
		return Point(y, -x);
	}
	Point rotate(Point p,double angle){
        Point v = (*this)-p;
        double c = cos(angle), s = sin(angle);
        return Point(p.x + v.x*c-v.y*s,p.y + v.x*s + v.y*c);
    }
}a[1010];
int len;
struct Line {
	Point s, e;
	Line(){
	}
	Line(Point s_, Point e_) {
		s = s_;
		e = e_;
	}
	
};
struct circle {
	Point p;
	double r;
	circle(){
	}
	circle(Point p_, double r_) {
		r = r_;
		p = p_;
	}
	int relationcircle(circle v) {
		double d = p.distance(v.p);
		if(sgn(d - r - v.r) > 0) return 5;
		if(sgn(d - r - v.r) == 0) return 4;
		double l = fabs(r - v.r);
		if(sgn(d - r - v.r) < 0 && sgn(d - l) > 0) return 3;
		if(sgn(d - l) == 0) return 2;
		if(sgn(d - l) < 0) return 1;
	}
	int getpoint(circle v, Point &p1, Point &p2) {
		int rel = relationcircle(v);
		if(rel == 1 || rel == 5) return 0;
		double d = p.distance(v.p);
		double l = (d * d + r * r - v.r * v.r) / (2 * d);
		double h = sqrt(r * r - l * l);
		Point tmp = p + (v.p - p).trunc(l);
		p1 = tmp + ((v.p - p).rotleft().trunc(h));
		p2 = tmp + ((v.p - p).rotright().trunc(h));
		if(rel == 2 || rel == 4) return 1;
		return 2;
	}
	int relation(Point b){
        double dst = b.distance(p);
        if(sgn(dst-r) < 0)return 2;
        else if(sgn(dst-r)==0)return 1;
        return 0;
    }

}C[1010];
int main() {
	int T, nn = 1;
	scanf("%d", &T);
	Point p1, p2, pp;
	int flag;
	double ans;
	while(T--) {
		scanf("%d %lf", &n, &R);
		C[0].p.x = 0;
		C[0].p.y = 0;
		C[0].r = R;
		len = 0;
		for(int i = 1; i <= n; i++) {
			scanf("%lf %lf %lf", &C[i].p.x, &C[i].p.y, &C[i].r);
			flag = C[0].getpoint(C[i], p1, p2);
			if(flag == 1) {
				len++;
				
				a[len] = p1;
			} else if(flag == 2) {
				len++;	
				a[len] = p2;
				
				len++;
				a[len] = p1;
			}
		}
		ans = 0;
		if(len == 0) {
			ans = R * 2;
		} else {
			for(int i = 1; i <= len; i++) {
				for(int j = i + 1; j <= len; j++)
					ans = max(ans, a[i].distance(a[j]));
				pp = Point(-a[i].x, -a[i].y);
				flag = 0;
				for(int j = 1; j <= n; j++) {
					if(C[j].relation(pp) <= 0) {
						flag++;
					} else break;
				}
				if(flag == n) {
				//	cout << a[i].x << " " << a[i].y << endl;
					ans = R * 2;
					break;
				}
			}
		}
		printf("Case #%d: %.15lf\n", nn++, ans);
	}
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值