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

题意:

有n个按先后顺序放置的不同大小不同位置的圆,求所有可见圆弧的长度。

分析:

这道题应该是大白书上例题 LA 2572 (求可见圆盘的数量) Kanazawa 的加强版,整体框架都差不多。

对于每个圆求出与其他圆相交的交点所对应的幅角(转化到[0, 2π]中),排个序,然后枚举每段弧的终点,如果不被后面放置的圆所覆盖则可见。

注意:

原本以为WA是精度问题,后来调大调小都一直WA,这里精度eps从1e-11到1e-13都没问题。

但是在判断弧的终点是否被圆所覆盖的时候要加上等号。也就是第64行代码中是<=而非<,一直被这个给坑惨了。

UVa的数据真的好强啊,Orz

  1 #include <cstdio>
  2 #include <cmath>
  3 #include <vector>
  4 #include <algorithm>
  5 using namespace std;
  6
  7 const int maxn = 100 + 10;
  8 const double eps = 1e-11;
  9 const double PI = acos(-1.0);
 10 const double TWO_PI = 2.0 * PI;
 11 double radius[maxn];
 12
 13 double NormalizeAngle(double ang)
 14 { return ang - TWO_PI*floor(ang/TWO_PI); }
 15
 16 int dcmp(double x)
 17 {
 18     if(fabs(x) < eps) return 0;
 19     return x < 0 ? -1 : 1;
 20 }
 21
 22 struct Point
 23 {
 24     double x, y;
 25     Point(double x=0, double y=0):x(x), y(y) {}
 26 }p[maxn];
 27 typedef Point Vector;
 28
 29 bool operator == (const Point& A, const Point& B)
 30 { return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0; }
 31
 32 Point operator - (const Point& A, const Point& B)
 33 { return Point(A.x - B.x, A.y - B.y); }
 34
 35 double Dot(const Point& A, const Point& B)
 36 { return A.x*B.x + A.y*B.y; }
 37
 38 double Length(const Vector& A)
 39 { return sqrt(Dot(A, A)); }
 40
 41 double Angle(const Vector& A)
 42 { return atan2(A.y, A.x); }
 43
 44 void GetCCIntersection(const Point& c1, double r1, const Point& c2, double r2, vector<double>& rad)
 45 {
 46     double d = Length(c1 - c2);
 47     if(dcmp(d) == 0) return;
 48     if(dcmp(d-r1-r2) > 0) return;
 49     if(dcmp(d-fabs(r1-r2)) < 0) return;
 50
 51     double base = Angle(c2 - c1);
 52     double ang = acos((r1*r1 + d*d - r2*r2) / (2.0*r1*d));
 53     rad.push_back(NormalizeAngle(base + ang));
 54     rad.push_back(NormalizeAngle(base - ang));
 55 }
 56
 57 int n;
 58
 59 bool isVisible(const Point& C, int id)
 60 {
 61     for(int i = id + 1; i < n; ++i)
 62     {
 63         double d = Length(C - p[i]);
 64         if(dcmp(d - radius[i]) <= 0) return false;    //这道题的关键所在
 65     }
 66     return true;
 67 }
 68
 69 int main(void)
 70 {
 71     //freopen("10969in.txt", "r", stdin);
 72     int T;
 73     scanf("%d", &T);
 74     while(T--)
 75     {
 76         scanf("%d", &n);
 77         for(int i = 0; i < n; ++i) scanf("%lf%lf%lf", &radius[i], &p[i].x, &p[i].y);
 78
 79         double sum = 0.0;
 80         for(int i = 0; i < n; ++i)
 81         {
 82             vector<double> rad;
 83             rad.push_back(0.0);
 84             rad.push_back(TWO_PI);
 85             for(int j = 0; j < n; ++j)
 86             {
 87                 if(j == i) continue;
 88                 GetCCIntersection(p[i], radius[i], p[j], radius[j], rad);
 89             }
 90             sort(rad.begin(), rad.end());
 91
 92             for(int j = 0; j < rad.size() - 1; ++j)
 93             {
 94                 double mid = (rad[j] + rad[j + 1]) / 2;
 95                 double ang = rad[j + 1] - rad[j];
 96                 Point C(p[i].x + radius[i]*cos(mid), p[i].y + radius[i]*sin(mid));
 97                 if(isVisible(C, i)) sum += radius[i] * ang;
 98             }
 99         }
100
101         printf("%.3f\n", sum);
102     }
103
104     return 0;
105 }

代码君

时间: 2024-10-26 08:30:07

UVa 10969 (圆与圆之间的覆盖问题) Sweet Dream的相关文章

uva 10969

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

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 的交点(同时考虑无交点和完全覆盖的情况),把交点按极角排序,然后就变成了区间覆盖问题了,给若干个区间,统计未被覆盖的长度(在此题实际上是角度)之和,然后就知

UVa 10674 (求两圆公切线) Tangents

题意: 给出两个圆的圆心坐标和半径,求这两个圆的公切线切点的坐标及对应线段长度.若两圆重合,有无数条公切线则输出-1. 输出是按照一定顺序输出的. 分析: 首先情况比较多,要一一判断,不要漏掉. 如果高中的那点老底还在的话,代码还是很好理解的. 1 //#define LOCAL 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #incl

uva 11177(凸多边形和圆的相交)

题意:按顺时针或逆时针顺序给出一个凸n边形的n个点的坐标,然后让一个圆心在(0,0)的圆和凸n边形相交的面积大于等于R,问圆的最小半径. 题解:这题简直坑爹啊,各种细节错误..修修改改了一天,最后看别人题解也还是不懂为什么OnSegment函数要写成那样...明明不能判断点是否在线段上 ╮(╯▽╰)╭ 画画图思路不难想到,把凸n边形的每条边都和圆判断关系,如果是边的两点都在圆内,两条边对应一个三角形的面积,如果一个点在圆外一个在圆内(包括边界),那就是一个三角形加一个扇形,如果两点都在圆外,分两

hdu4063(圆与圆交+线段与圆交+最短路)

写几何题总是提心吊胆.精度问题真心吓人. 其实思路挺简单的一道题,真是什么算法和几何double搞到一块,心里就虚虚的. 思路:求出所有圆之间的交点,然后用这些交点跑一遍最短路就可以了. Aircraft Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1244    Accepted Submission(s): 304 Proble

bzoj2289: 【POJ Challenge】圆,圆,圆

Description 1tthinking随便地画了一些圆. ftiasch认为这些圆有交集(面积非零)的可能性不大.因为他实在画了太多圆,所以你被请来判断是否存在交集. Input 第1行,一个整数 N (1 ≤ N ≤ 105), 圆的数量. 第2到 N 行: 三个整数 Xi, Yi, Ri, 圆心在 (Xi, Yi), 半径为 Ri 的圆. Output 如果存在面积非零的交集,则输出 "YES",否则输出 "NO". 首先可以确定如果有相交,x坐标一定在区

uva 10020 Minimal coverage(贪心,区间覆盖)

这道题一读就是经典的区间问题,是区间覆盖,敲过之后还有花了很长的调试时间,还是我不熟练,现在做题确实挺慢 的,简单题目也要做好久,没事,慢慢来.最重要的要确保正确率和心态问题,认真对待,调试找到了好多bug,一些 细节问题...都是刚开始没有注意到的.交了之后RE,在数组上多加了两个0.A了,,uva老是不提示数据有多大, 所以只能乱开... 思路: 先对区间按左边的点进行排序,如果当前需要涵盖的区间为[x,y],那么在排序的区间中到左边小于x,右 边最大的那个区间,设为Max,然后更新想找的区

中秋节愿月圆人圆家也圆,人旺财旺前途旺。

盛夏已退,秋凉如水,光阴荏苒,岁月如梭,转眼间又是一年中秋节. 中秋节始于唐朝初年,盛行于宋朝,至明清时,已成为与春节齐名的中国主要节日之一.自2008年起中秋节被列为国家法定节假日.2006年5月20日,国务院列入首批国家级非物质文化遗产名录. 中秋节自古便有祭月.赏月.拜月.吃月饼.赏桂花.饮桂花酒等习俗,流传至今,经久不息.中秋节以月之圆兆人之团圆,为寄托思念故乡,思念亲人之情,祈盼丰收.幸福,成为丰富多彩.弥足珍贵的文化遗产.中秋节与端午节.春节.清明节并称为中国四大传统节日. 中秋节

UVA - 11214 Guarding the Chessboard (可重复覆盖,DLX+IDA*)

题目链接 正解是IDA*+四个方向判重,但由于是个裸的可重复覆盖问题,可以用DLX水过~ 每个格子与放上皇后能干掉的标记连边,跑可重复覆盖DLX.注意要用IDA*来优化,否则会超时. 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=10+2; 5 int n,m,np,ka; 6 char s[N][N]; 7 struct P {int x,y;} p[N*N]; 8