uva 10969 - Sweet Dream(几何)求圆弧是否被覆盖

题目链接:https://vjudge.net/problem/UVA-10969

题目大意:

给出多个圆,按顺序输入,下层圆会被后来的上层的圆覆盖住,问最后从上往下看,能看到的圆弧的长度

题目解析:

从最下层的圆开始,求出该圆与其上层圆的所有交点,然后对这些交点从小到大进行极角排序

从最小的点开始,与其后一个相邻的点为一组,求出以这两点划分出的弧的中点,然后将这个中点与上层所有的圆进行比较,看是否能被圆包含,如果能被包含,说明这段弧是被圆覆盖住的,不可见(确实是这样)。将所有可见弧的长度相加,即为所求

这道题做的时候想的是用交点划分出的弧作为区间,然后让区间进行叠加,最后求出总的区间的对应的角度,有点偏重模拟了,写起来十分繁琐复杂

计算几何做起来还是画画图更清晰,一开始没想通为什么是中点被圆包含就算整段弧都被圆覆盖,后来画个图一看就想通了

 

AC代码:

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;

int n,m;
const double PI=acos(-1.0);
const double eps=1e-6;
const double TWO_PI = 2.0 * PI;
//double radius[1000];

double NormalizeAngle(double ang){ //防止角度大于2PI 
	return ang - TWO_PI*floor(ang/TWO_PI);
}

struct Point{
	double x,y;
	Point(double x=0,double y=0):x(x),y(y){}
};

double radius[1000];

typedef Point Vector;

Point P[1000];

int sgn(double d){
	if(fabs(d)<eps){//等于零 
		return 0;
	}
	if(d<0){		//大于零 
		return -1;
	}
	return 1;		//小于零 
}

double Dot(const Point& A, const Point& B)
{ return A.x*B.x + A.y*B.y; }

double Length(const Vector& A)
{ return sqrt(Dot(A, A)); }

double Cross(Vector A,Vector B){
	return A.x*B.y-A.y*B.x;
}

double getAngle(Vector A,Vector B){//得到两向量弧度制下的夹角 
	return fabs(atan2(A.y,A.x)-atan2(B.y,B.x));
} 
double Angle(const Vector& A){ 
	return atan2(A.y, A.x); 
}//获得单个向量的角度 
bool cmp1(Vector A,Vector B)
{
    if(atan2(A.y,A.x)!=atan2(B.y,B.x))
        return atan2(A.y,A.x)<atan2(B.y,B.x);
    else return A.x<B.x;
}

bool operator == (const Point& A, const Point& B)
{ return sgn(A.x - B.x) == 0 && sgn(A.y - B.y) == 0; }

Point operator - (const Point& A, const Point& B)
{ return Point(A.x - B.x, A.y - B.y); }


void getCircleIntersection(const Point &c1,double r1,const Point &c2,double r2,vector<double> &rad){
	double d=Length(c1-c2);
	if(sgn(d)==0) return;
	if(sgn(d-r1-r2)>0) return;
	if(sgn(d-fabs(r1-r2))<0) return;
	
	double base=Angle(c2-c1);
	double ang=acos((r1*r1+d*d-r2*r2)/(2.0*r1*d));
	rad.push_back(NormalizeAngle(base+ang));
	rad.push_back(NormalizeAngle(base-ang)); 
}

bool isVisible(const Point &C,int id){
	for(int i=id+1;i<n;i++){
		double d=Length(C-P[i]);
		if(sgn(d-radius[i])<=0){
			return 0;
		}
	}
	return 1;
}

int main() {
	cin>>m;
	for(int i=1;i<=m;i++){
		cin>>n;
		for(int j=0;j<n;j++){
			cin>>radius[j]>>P[j].x>>P[j].y;
		}
		double  ans=0.0;
		for(int j=0;j<n;j++){
			vector<double> rad;
			rad.push_back(0.0);
			rad.push_back(TWO_PI);
			for(int k=0;k<n;k++){
				if(k==j){
					continue;
				}
				getCircleIntersection
				(P[j],radius[j],P[k],radius[k],rad);
			}
			sort(rad.begin(),rad.end());
			for(int k=0;k<rad.size()-1;k++){
				double mid=(rad[k]+rad[k+1])/2;
				double ang=(rad[k+1]-rad[k]);
				Point C(P[j].x+radius[j]*cos(mid),
				P[j].y+radius[j]*sin(mid));
				if(isVisible(C,j)){
					ans+=radius[j]*ang;
				}
			}
		}
		printf("%.3f\n",ans);
	}
	return 0;
}

/*
3
1
10 0 0
2
5 0 0
10 0 0
2
1 0 0
1 1 0

*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值