BZOJ 1043: [HAOI2008]下落的圆盘

Description

求几个圆交起来的周长..\(n\leqslant 10^3\)

Solution

计算几何.

圆圆求交..

Code

/**************************************************************
    Problem: 1043
    User: BeiYu
    Language: C++
    Result: Accepted
    Time:520 ms
    Memory:1308 kb
****************************************************************/

#include <bits/stdc++.h>
using namespace std;

namespace CG {
    typedef double LD;

    const LD Pi = M_PI;
    const LD PI = 2 * acos(0.0);
    const LD eps = 1e-12;
    #define sqr(x) ((x)*(x))

    int dcmp(LD x) { return fabs(x)<eps?0:(x<0?-1:1); }

    struct Point {
        LD x,y;
        Point(LD _x=0,LD _y=0) :x(_x),y(_y) {}
        void out() { cout<<"("<<x<<","<<y<<")"; }
    };
    typedef Point Vector;

    int cmpx(const Point &a,const Point &b) { return dcmp(a.x-b.x)==0?a.y<b.y:a.x<b.x; }

    Vector operator + (const Vector &a,const Vector &b) { return Vector(a.x+b.x,a.y+b.y); }
    Vector operator - (const Vector &a,const Vector &b) { return Vector(a.x-b.x,a.y-b.y); }
    Vector operator * (const Vector &a,LD b) { return Vector(a.x*b,a.y*b); }
    Vector operator / (const Vector &a,LD b) { return Vector(a.x/b,a.y/b); }
    bool operator == (const Point &a,const Point &b) { return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; }

    LD Dot(Vector a,Vector b) { return a.x*b.x+a.y*b.y; }
    LD Cross(Vector a,Vector b) { return a.x*b.y-b.x*a.y; }
    Vector Rot(Vector a,LD rd) { return Vector(a.x*cos(rd)-a.y*sin(rd),a.x*sin(rd)+a.y*cos(rd)); }
    LD get_l(Vector a) { return sqrt(Dot(a,a)); }
    LD get_d(Point a,Point b) { return sqrt(Dot(a-b,a-b)); }
    LD get_a(Vector a) { return atan2(a.y,a.x); }
    LD get_a(Vector a,Vector b) { return acos(Dot(a,b)/get_l(a)/get_l(b)); }
    LD get_s(Point a,Point b,Point c) { return Cross(b-a,c-a)/2.0; }

    struct Line {
        Point p;
        Vector v;
        Line(Point a=Point(),Point b=Point()):p(a),v(b-a) {  }
        LD get_l() { return sqrt(Dot(v,v)); }
        Point get_p(LD t) { return p+v*t; }
        Point get_s() { return p; }
        Point get_t() { return p+v; }
    };

    struct Circle {
        Point c;
        LD r;
        Point get_p(LD t) { return c+Point(cos(t)*r,sin(t)*r); }
        LD get_rd(Point a,Point b) { return get_a(a-c,b-c); }
        LD get_l(LD rd) { return r*rd; }
    };

    int get_c_l(Line L,Circle C,vector<Point> &res) {
        LD a=L.v.x,b=L.p.x-C.c.x,c=L.v.y,d=L.p.y-C.c.y;
        LD e=sqr(a)+sqr(c),f=2.0*(a*b+c*d),g=sqr(b)+sqr(d)-sqr(C.r);
        LD dt=f*f-4*e*g;
        if(dcmp(dt)<0) return 0;
        if(dcmp(dt)==0) return res.push_back(L.get_p(-f/(2.0*e))),1;
        LD x1=(-f-sqrt(dt))/(2.0*e),x2=(-f+sqrt(dt))/(2.0*e);
        if(x1>x2) swap(x1,x2);
        res.push_back(L.get_p(x1)),res.push_back(L.get_p(x2));return 2;
    }
    int get_c_c(Circle A,Circle B,vector<Point> &res) {
        LD d=get_l(A.c-B.c);
        if(dcmp(d)==0) return dcmp(A.r-B.r)==0?-1:0;
        if(dcmp(A.r+B.r-d)<0) return 0;
        if(dcmp(fabs(A.r-B.r)-d)>0) return 0;

        LD a=get_a(B.c-A.c);
        LD rd=acos((sqr(A.r)+sqr(d)-sqr(B.r))/(2.0*A.r*d));

        Point p1,p2;
        p1=A.get_p(a+rd),p2=A.get_p(a-rd);

        res.push_back(p1);
        if(p1==p2) return 1;
        res.push_back(p2);
        return 2;
    }

    /*---io---*/
    ostream & operator << (ostream &os,const Point &p) { os<<p.x<<" "<<p.y;return os; }
    istream & operator >> (istream &is,Point &p) { is>>p.x>>p.y;return is; }
    ostream & operator << (ostream &os,const Circle &C) { os<<C.c<<" "<<C.r;return os; }
    istream & operator >> (istream &is,Circle &C) { is>>C.c>>C.r;return is; }
};

using namespace CG;

#define mpr make_pair

int n;
LD ans;
vector<Circle> cr;
vector<Line> cl;
vector<Point> ls;
vector<Point> cp;

void add_l(vector<Point> &s,LD x,LD y) {
    if(x>y) s.push_back(Point(x,Pi)),s.push_back(Point(-Pi,y));
    else ls.push_back(Point(x,y));
}
int chk(Circle A,Circle B) {
    LD d=get_l(A.c-B.c);
    if(dcmp(B.r-A.r-d)>0) return 1;
    return 0;
}
LD get_ans(Circle c,int id) {
    ls.clear();
    //O-O jiaodian
    for(int i=id+1;i<n;i++) {
        cp.clear();
        if(chk(c,cr[i])) return 0;
        if(get_c_c(c,cr[i],cp)<2) continue;
        LD xx=get_a(cp[0]-c.c),yy=get_a(cp[1]-c.c);
        add_l(ls,yy,xx);
    }
    if(!ls.size()) return c.get_l(2*Pi);
    sort(ls.begin(),ls.end(),cmpx);
//  for(int i=0;i<(int)ls.size();i++) cout<<ls[i].x<<" "<<ls[i].y<<endl;
    LD lx=ls[0].x,ly=lx,res=0;
    for(int i=0;i<(int)ls.size();i++) {
        if(dcmp(ls[i].x-ly)>0) res+=ly-lx,lx=ls[i].x;
        ly=max(ly,ls[i].y);
    }res+=ly-lx;
    return c.get_l(2*Pi-res);
}
void Solve() {
    scanf("%d",&n);
    Circle cc;
    cr.clear(),ls.clear(),cp.clear(),ans=0;

    for(int i=1;i<=n;i++) {
        scanf("%lf%lf%lf",&cc.r,&cc.c.x,&cc.c.y);
        cr.push_back(cc);
    }
    for(int i=0;i<n;i++) {
        LD tmp=get_ans(cr[i],i);
        ans+=tmp;
    //  cout<<tmp<<endl;
    }printf("%.3lf\n",ans);
}

int main() {
    Solve();
    return 0;
}

  

时间: 2024-10-26 01:13:32

BZOJ 1043: [HAOI2008]下落的圆盘的相关文章

BZOJ 1043 HAOI2008 下落的圆盘 计算几何

题目大意:n个圆盘依次下落.求终于能看到的轮廓线面积 円盘反对! 让我们一起团结起来! 赶走円盘! 咳咳.非常神的一道题 今天去看了题解和白书才搞出来-- 首先我们倒着做 对于每一个圆盘处理出在它之后落下的圆盘和它的覆盖区间 然后求一个区间并就能算出这个圆盘的可见弧长 然后就是相交部分怎么求的问题了 首先两个圆必须相交 然后作圆心1到圆心2的向量 用atan2求出极角 然后利用余弦定理求出两个交点和圆心连线的夹角就可以 注意区间不在[0,2π]的部分要切割成还有一个区间 处理起来事实上不是非常麻

【BZOJ】1043: [HAOI2008]下落的圆盘(计算几何+贪心)

http://www.lydsy.com/JudgeOnline/problem.php?id=1043 唯一让我不会的就是怎么求圆的周长并QAAQ... 然后发现好神!我们可以将圆弧变成$[0, 2 \pi ]$的直线! 然后一定要注意!起点是$(1, 0)$(单位圆) 首先学了余弦定理... 在三角形ABC中 $$cos A=\frac{|AB|^2+|AC|^2-|BC|^2}{2|AB| |AC|}$$ 证明很简单... $$\begin{align}|{BC}|^2 & = \vec{

bzoj1043[HAOI2008]下落的圆盘 计算几何

1043: [HAOI2008]下落的圆盘 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1598  Solved: 676[Submit][Status][Discuss] Description 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红色线条的总长度即为所求.  Input 第一行为1个整数n,N<=1000接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标

【BZOJ1043】[HAOI2008]下落的圆盘 几何

[BZOJ1043][HAOI2008]下落的圆盘 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 题解:对于每个圆,我们枚举它后面的

BZOJ1043:[HAOI2008]下落的圆盘——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=1043 Description 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红 色线条的总长度即为所求. Input 第一行为1个整数n,N<=1000 接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标. Output 最后的周长,保留三位小数 Sample Input 2 1 0 0 1 1 0 Sample Out

【bzoj1043】[HAOI2008]下落的圆盘 计算几何

题目描述 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红色线条的总长度即为所求. 输入 第一行为1个整数n,N<=1000接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标. 输出 最后的周长,保留三位小数 样例输入 2 1 0 0 1 1 0 样例输出 10.472 题解 计算几何 考虑从下到上的每一个圆,它被其它的圆覆盖了多少.即考虑它被覆盖了多少弧度. 考虑两个圆,如果相离则不覆盖,内含判断一下包含关系. 如果

BZOJ1043 [HAOI2008]下落的圆盘

倒过来做,然后就变成了线段覆盖问题了. 线段覆盖就是贪心即可... 但是好烦好烦= =,需要耐心和几何基础2333 1 /************************************************************** 2 Problem: 1043 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:240 ms 7 Memory:872 kb 8 ****************************

【bzoj_1043】[HAOI2008]下落的圆盘

水题?好像是的.(可惜我不会,默默捂脸= ̄ω ̄= 首先明确一点.两个圆相交,圆上的弧一定是从du-ang到du+ang的,不管是优弧还是劣弧.(du代表两圆心连线的atan2值,ang就是用余弦定理算出来的那个角) 然后就爽了. 把所有圆后面的圆扫一遍,看看有哪些焦点,用角度的形式记录下有哪些弧被覆盖,然后求并. 注意范围必须映射到一个长度为2π的区间内,否则求并的时候会出问题.

JZYZOJ1502 [haoi2008]下落的圆盘 计算几何 贪心

http://172.20.6.3/Problem_Show.asp?id=1502这种题用了快一天才写出来也是真的辣鸡.主要思路就是计算一下被挡住的弧度然后对弧度进行贪心.最开始比较困扰的是求弧度值及其起始位置的部分,弧度值很好求,位置有点恶心,我的起始位置设置的是圆的十二点方向顺时针到起始位置的弧度值,然后我分了四种情况讨论(因为遮挡的方向有两种不同情况,遮挡部分弧度值与180度的关系又是两种情况),应该是有更简单的方法的,但是我只能想出来这种了... 代码 1 #include<cstdi