UVA - 10969 Sweet Dream

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34782

Problem

从楼上往下丢N个圆,告诉圆的半径和落点,求最终图形的可见弧长之和。N<=100

Solution

实际上可以转换为圆求交。逆着来,i : n->1,j : i+1->n,求出 i 与 j 的交点(同时考虑无交点和完全覆盖的情况),把交点按极角排序,然后就变成了区间覆盖问题了,给若干个区间,统计未被覆盖的长度(在此题实际上是角度)之和,然后就知道此圆最终显示的弧长了。

圆和圆相交要有特殊的技巧,此题不需要把交点求出来,只要知道交点的极角即可。极角处理还有特殊的技巧,当a<0(a表示极角)时候,a+=2*pi。区间覆盖也有特殊技巧,可能出现环的情况,即区间穿过x轴正方向,拆成两个区间即可。

我还是认为,大白书第一章里很多东西十分重要,计算几何里高频率出现区间覆盖问题。

具体怎么做,看代码吧(主要参考大白书的模板,感谢lrj和凤神代码的指导)

My code

//Hello. I'm Peter.
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define MAXN
#define N 2015
#define M
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const double eps=1e-10,pi=acos(-1.0);
inline int dcmp(double x){
    if(fabs(x)<eps) return 0;
    else if(x<0) return -1;
    else return 1;
}
struct Point{
    double x,y;
    Point(){};
    Point(double xx,double yy){
        x=xx;
        y=yy;
    }
};
typedef Point Vector;
double angle(Vector v){
    return atan2(v.y,v.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);
}
double operator *(const Vector a,const Vector b){
    return a.x*b.x+a.y*b.y;
}
Vector operator*(const Vector a,const double b){
    return Vector(a.x*b,a.y*b);
}
Vector operator*(const double b,const Vector a){
    return Vector(a.x*b,a.y*b);
}
double operator%(const Vector a,const Vector b){
    return a.x*b.y-a.y*b.x;
}
bool operator==(const Vector a,const Vector b){
    return !dcmp(a.x-b.x)&&!dcmp(a.y-b.y);
}
double Length(Vector v){
    return sqrt(v.x*v.x+v.y*v.y);
}
struct Circle{
    double r;
    Point c;
    Circle(){};
    Circle(Point cc,double rr){
        c=cc;
        r=rr;
    }
    Point point(double a){
        return Point(c.x+r*cos(a),c.y+r*sin(a));
    }
}c[N];
inline void CircleInterCircle(Circle c1,Circle c2,double *temp,int& numtemp){
    if(!dcmp(c1.r-c2.r)&&c1.c==c2.c){//重合
        numtemp=-1;
        return;
    }
    double dis=Length(c1.c-c2.c);
    if(dcmp(dis-(c1.r+c2.r))>=0){
        //相离或外切
        numtemp=0;
        return;
    }
    if(dcmp(fabs(c1.r-c2.r)-dis)>=0){
        //内含或内切
        if(dcmp(c1.r-c2.r)<=0) numtemp=-1;//c2包住了c1
        else numtemp=0;
        return;
    }
    //相交
    Vector v=c2.c-c1.c;
    double a=angle(v);
    double b=acos((c1.r*c1.r+dis*dis-c2.r*c2.r)/(2*c1.r*dis));
    temp[0]=a+b;
    temp[1]=a-b;
    numtemp=2;
}
bool PointInCircle(Point p,Circle c){
    return dcmp(Length(p-c.c)-c.r)<=0;
}
struct Data{
    double a;
    bool in;
}data[N];
double temp[10];
int n,numtemp,numdata;
inline bool comp(const Data A,const Data B){
    if(dcmp(A.a-B.a)) return A.a<B.a;
    else return A.in>B.in;
}
int main(){
    int T=read();
    while(T--){
        n=read();
        for(int i=1;i<=n;i++){
            scanf("%lf%lf%lf",&c[i].r,&c[i].c.x,&c[i].c.y);
        }
        double ans=0.0;
        for(int i=1;i<=n;i++){
            numdata=0;
            bool pass=false;
            for(int j=i+1;j<=n;j++){
                CircleInterCircle(c[i],c[j],temp,numtemp);
                if(numtemp==0) continue;
                if(numtemp==-1){
                    pass=true;
                    break;
                }
                if(dcmp(temp[0])<0) temp[0]+=2*pi;
                if(dcmp(temp[1])<0) temp[1]+=2*pi;
                if(dcmp(temp[0]-temp[1])>0) swap(temp[0],temp[1]);
                //temp all >0 temp[0]<temp[1]
                double mi=(temp[0]+temp[1])*0.5;
                Point pmi=c[i].point(mi);
                int t;
                if(PointInCircle(pmi,c[j])){
                    t=++numdata;
                    data[t].a=temp[0];
                    data[t].in=true;
                    t=++numdata;
                    data[t].a=temp[1];
                    data[t].in=false;
                }
                else{
                    t=++numdata;
                    data[t].a=0;
                    data[t].in=true;
                    t=++numdata;
                    data[t].a=temp[0];
                    data[t].in=false;

                    t=++numdata;
                    data[t].a=temp[1];
                    data[t].in=true;
                    t=++numdata;
                    data[t].a=2*pi;
                    data[t].in=false;
                }
            }
            if(pass) continue;
            double uncover=0.0;
            data[++numdata].a=2*pi;
            data[numdata].in=false;
            sort(data+1,data+1+numdata,comp);
            double lasta=0.0;
            int num=0;
            for(int k=1;k<=numdata;k++){
                if(!num) uncover+=data[k].a-lasta;
                lasta=data[k].a;
                num+=data[k].in?1:-1;
            }
            uncover*=c[i].r;
            ans+=uncover;
        }
        printf("%.3f\n",ans);
    }
    return 0;
}

你可能感兴趣的:(极角,计算几何,区间覆盖,圆相交)