• 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
    ",ans);
    	return 0;
    }
  • 相关阅读:
    ckeditor详解
    c#实现生产者消费者模式
    逻辑思维题01
    关于nginx的安装
    一些关于python的小感想
    关于linux上pdf阅读器
    将python2.7+django1.10部署到SAE上
    配置github上的SSH key及上传自己的项目到github
    解决ubuntu15 下没有声音
    linux小倒腾
  • 原文地址:https://www.cnblogs.com/chezhongyang/p/7701798.html
Copyright © 2020-2023  润新知