zoukankan      html  css  js  c++  java
  • [bzoj] 1043 下落的圆盘 || 圆上的“线段覆盖”

    原题

    n个圆盘,求下落后能看到的总周长。

    红色即为所求


    借鉴于黄学长的博客
    对于每下落的一个圆盘,处理他后面的圆盘会挡住哪些区域,然后把一整个圆(2(/pi))当做一整个区间,每个被覆盖的部分都可以化为一条线段,做线段覆盖就可以得到最后这个圆对答案的贡献了。

    详解见代码。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define pi acos(-1)
    #define N 1010
    typedef long long ll;
    using namespace std;
    int n,top;
    double ans,x[N],y[N],r[N];
    struct line
    {
        double l,r;
        line() {}
        line(double x,double y) : l(x),r(y) {}
        line(int x,double y) : l(x),r(y) {}//鬼畜的构造函数……
        bool operator < (const line b) const
    	{
    	    return l<b.l;
    	}
    }q[N];
    
    inline double dis(int a,int b)
    {
        return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
    }
    
    bool conta(int a,int b)//判断b圆有没有被a圆完全覆盖
    {
        if (r[a]>=r[b]+dis(a,b)) return 1;
        return 0;
    }
    
    void inter(int a,int b)
    {
        double d,t,st,l;
        d=dis(a,b);
        t=(r[a]*r[a]-r[b]*r[b]+d*d)/(2*d*r[a]);//余弦定理求角(位置见上图)
        st=atan2((x[a]-x[b]),(y[a]-y[b]));
        l=acos(t);
        q[++top]=line(st-l,st+l);//以弧的两个端点当做线段的两个端点
    }
    
    double cal(int x)//求第x个圆最后能看到的周长
    {
        for (int i=x+1;i<=n;i++)
    	if (conta(i,x)) return 0;//如果被其他圆覆盖,就没有贡献
        top=0;
        for (int i=x+1;i<=n;i++)
    	if (!conta(x,i) && r[x]+r[i]>=dis(x,i))//这两个圆相交
    	    inter(x,i);//求出被覆盖的部分并简化为线段
        double tmp=0,now=0;
        for (int i=1;i<=top;i++)//把角度都处理到[0,$2/pi$)中
        {
    	if (q[i].l<0) q[i].l+=2*pi;
    	if (q[i].r<0) q[i].r+=2*pi;
    	if (q[i].l>q[i].r)
    	{
    	    q[++top]=line(0,q[i].r);
    	    q[i].r=2*pi;
    	}
        }
        sort(q+1,q+top+1);
        for (int i=1;i<=top;i++)//线段覆盖
    	if (q[i].l>now)
    	{
    	    tmp+=q[i].l-now;
    	    now=q[i].r;
    	}
    	else now=max(now,q[i].r);
        tmp+=2*pi-now;
        return r[x]*tmp;//能看到的长度
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
    	scanf("%lf%lf%lf",&r[i],&x[i],&y[i]);
        for (int i=1;i<=n;i++)
    	ans+=cal(i);
        printf("%.3f",ans);
        return 0;
    }
    
  • 相关阅读:
    Inno Setup入门(十三)——Pascal脚本(2)
    Inno Setup入门(十二)——Pascal脚本(1)
    Inno Setup入门(十一)——完成安装后执行某些程序
    Inno Setup入门(一)——最简单的安装脚本
    用现代化的方式开发一个图片上传工具
    现在就可以使用的5个 ES6 特性
    PhantomJS 基础及示例
    jquery获取css颜色值返回RGB应用
    Javascript常见设计模式解析
    更合理的 setState()
  • 原文地址:https://www.cnblogs.com/mrha/p/8118259.html
Copyright © 2011-2022 走看看