QQ联系我

BZOJ 1043: [HAOI2008]下落的圆盘

1043: [HAOI2008]下落的圆盘

Time Limit: 10 Sec  Memory Limit: 162 MB

Submit: 1533  Solved: 644

[Submit][Status][Discuss]

Description

  有n个圆盘从天而降,后面落下的可以盖住前面的。求最后形成的封闭区域的周长。看下面这副图, 所有的红色线条的总长度即为所求.

Input

  第一行为1个整数n,N<=1000
接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标.

Output

  最后的周长,保留三位小数

Sample Input

2
1 0 0
1 1 0

Sample Output

10.472

题解

n<=1000,n^2可做,按顺序枚举每个圆,再依次枚举之后的所有圆,用数组维护圆上被覆盖的弧度范围,最后类似线段覆盖求出覆盖总和,就可以算出最后可见的长度。

细节:

1.如果当前圆被后面某个圆完全覆盖,那么不考虑和其他圆相交。

2.覆盖的弧度范围要处理一下,如果弧度<0,那么弧度+2π,如果加了之后l>r,那么将l-r拆成0-r和l-2π两段。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=1005;
const double pi=acos(-1.0);
int n,top;
double ans;
struct stack{
	double l,r;
}st[N];
struct cir{
	double r,x,y;
}c[N];
double sqr(double a){
	return a*a;
}
double dis(cir a,cir b){
	return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
bool cover(cir a,cir b){
	if(a.r>=b.r+dis(a,b))return true;
	return false;
}
bool cross(cir a,cir b){
	if(a.r+b.r>dis(a,b))return true;
	return false;
}
void work(cir a,cir b){
	double dist=dis(a,b);
	double ang=acos((sqr(a.r)+sqr(dist)-sqr(b.r))/(2*a.r*dist));
	double std=atan2((b.y-a.y),(b.x-a.x));
	st[++top]=(stack){std-ang,std+ang}; 
}
bool cmp(stack a,stack b){
	return a.l==b.r?a.r<b.r:a.l<b.l;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lf%lf%lf",&c[i].r,&c[i].x,&c[i].y);
	}
	int fg;
	double l,r;
	for(int i=1;i<=n;i++){
		fg=0;
		for(int j=i+1;j<=n;j++){
			if(cover(c[j],c[i])){
				fg=1;
				break;
			}
		}
		if(fg)continue;
		top=0;
		for(int j=i+1;j<=n;j++){
			if(cross(c[i],c[j])&&!cover(c[i],c[j]))work(c[i],c[j]);
		}
		for(int j=1;j<=top;j++){
			while(st[j].l<0)st[j].l+=2*pi;
			while(st[j].r<0)st[j].r+=2*pi;
			if(st[j].l>st[j].r){
				st[++top]=(stack){0,st[j].r};
				st[j].r=2*pi;
			}
		}
		st[++top]=(stack){2*pi,2*pi};
		sort(st+1,st+top+1,cmp);
		l=r=0;
		for(int j=1;j<=top;j++){
			if(st[j].l<r){
				if(st[j].r>r)r=st[j].r;
				continue;
			}
			ans-=(r-l)*c[i].r;
			l=st[j].l;
			r=st[j].r;
		}
		ans+=2*pi*c[i].r;
	} 
	printf("%.3lf\n",ans);
	return 0;
}
posted @ 2017-10-20 21:46  czy020202  阅读(115)  评论(0编辑  收藏  举报