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;
}
时间: 2024-10-26 09:10:41

UVA - 10969 Sweet Dream的相关文章

UVA 10497 - Sweet Child Makes Trouble(DP+高精度)

题目链接:10497 - Sweet Child Makes Trouble 题意:n个物品,原来物品属于一个地方,现在要把物品重新放回去,问能放几种使得每个物品都与原来位置不同 思路:递推,一开始随便搞了个二维状态,dp[i][j]表示i个物品,有j个位置不同,那么dp[n][n]就是答案,递推式为: dp[i][j] = 1 (j == 0) dp[i][j] = (j - 1) * dp[i - 1][j - 1] + dp[i - 1][j] + (i - j + 1) * dp[i -

UVA - 10497 Sweet Child Makes Trouble

Children are always sweet but they can sometimesmake you feel bitter. In this problem, you will see how Tintin, a five year'sold boy, creates trouble for his parents. Tintin is a joyful boy and is alwaysbusy in doing something. But what he does is no

uva 10497 - Sweet Child Makes Trouble(dp+高精度)

题目链接:uva 10497 - Sweet Child Makes Trouble 题目大意:有个小屁孩很淘气,总是趁父母不在家的时候去拿家具玩,每次拿n个家具玩,但是放回去的时候一定不会将某个物品放回原处,一定要打乱.问说有多少放的方式满足. 解题思路:dp[i]表示说i个数打乱的情况,dp[i]=(dp[i?1]+dp[i?2])?(i?1)每次新增一个数,放在序列的最后一个位置,它的位置一定是正确的,所以一定要和前面i?1个的其中一个交换位置才可以,那么如果选中位置上的物品为错误归放的,

UVa 10969 (圆与圆之间的覆盖问题) Sweet Dream

题意: 有n个按先后顺序放置的不同大小不同位置的圆,求所有可见圆弧的长度. 分析: 这道题应该是大白书上例题 LA 2572 (求可见圆盘的数量) Kanazawa 的加强版,整体框架都差不多. 对于每个圆求出与其他圆相交的交点所对应的幅角(转化到[0, 2π]中),排个序,然后枚举每段弧的终点,如果不被后面放置的圆所覆盖则可见. 注意: 原本以为WA是精度问题,后来调大调小都一直WA,这里精度eps从1e-11到1e-13都没问题. 但是在判断弧的终点是否被圆所覆盖的时候要加上等号.也就是第6

递推+高精度 UVA 10497 Sweet Child Makes Trouble(可爱的孩子惹麻烦)

题目链接 题意: n个物品全部乱序排列(都不在原来的位置)的方案数. 思路: dp[i]表示i个物品都乱序排序的方案数,所以状态转移方程.考虑i-1个物品乱序,放入第i个物品一定要和i-1个的其中一个交换位置,即:考虑i-2个物品乱序,第i-1个和第i个首先在原来的位置,两种方法使得乱序,一种和第i个交换(不能和前i-2个交换,那样成dp[i-1]),还有一种是第i个先和第i-1个交换,再和前i-2个其中一个交换,即,仔细想想,这个和dp[i-1]是不同的交换方法. 另外: 还有二维的dp写法,

uva 10969

题意:平面上依次放置n个圆,后放的覆盖先放的,按顺序给出每个圆的半径和圆心坐标,问最后图形的可见圆弧长之和. 题解:因为是后放的覆盖先放的,所以逆序枚举,每个圆只考虑之前放过的圆和自己的交点,把所有交点排序后可以得到每两个相邻的交点之间的圆弧,找到圆弧中点,如果这个点在之前放过的圆内,说明这个圆弧不能要,否则加到答案里.注意弧度要规范到0-2π. #include <cstdio> #include <cstring> #include <cmath> #include

dp题目列表

10271 - Chopsticks 10739 - String to Palindrome 10453 - Make Palindrome 10401 - Injured Queen Problem 825 - Walking on the Safe Side 10617 - Again Palindrome 10201 - Adventures in Moving - Part IV 11258 - String Partition 10564 - Paths through the Ho

函数调用---JS权威指南

四种调用方式: 作为函数 作为方法 作为构造函数 (待续) 通过它们的call()和apply()方法调用 (待续) 函数调用:就是将函数作为普通的函数进行调用. 根据ES3和非严格的ES5的规定,函数调用的上下文(this)是全局对象.在严格模式下,调用上下文是undefined.后面的代码中会看到. this 也可以用来判断是否是严格模式, var strict = (function(){return !this;}()); 方法调用(今晚重点): 方法简单的说就是对象的一个属性,只不过这

推荐29首,非常适合80后结婚用的好听歌曲

推荐29首,适合80后结婚用的歌曲 1:Sweet Dream 原因:Sweet Dream是由韩国张娜拉所唱的,非常适合婚礼所用,有几对明星结婚都是用这首歌. 2:Light Of My Life 原因:Light Of My Life是由Lara Fabian & 王力宏 合唱的,收录在<云霄恋曲>里,这是一张不同组合的合唱歌曲专集,其中大部分歌曲都可以作为婚礼音乐.重点推荐这首 3:I SWEAR 原因:这首歌是讲男孩向女孩发誓,会一生一世相守,就象天上的星星和月亮每夜都会一同挂