您的位置:首页 > 其它

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

2014-12-07 00:49 267 查看
题意:

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

分析:

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

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

注意:

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

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

UVa的数据真的好强啊,Orz

#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

const int maxn = 100 + 10;
const double eps = 1e-11;
const double PI = acos(-1.0);
const double TWO_PI = 2.0 * PI;
double radius[maxn];

double NormalizeAngle(double ang)
{ return ang - TWO_PI*floor(ang/TWO_PI); }

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

struct Point
{
double x, y;
Point(double x=0, double y=0):x(x), y(y) {}
}p[maxn];
typedef Point Vector;

bool operator == (const Point& A, const Point& B)
{ return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0; }

Point operator - (const Point& A, const Point& B)
{ return Point(A.x - B.x, A.y - B.y); }

double Dot(const Point& A, const Point& B)
{ return A.x*B.x + A.y*B.y; }

double Length(const Vector& A)
{ return sqrt(Dot(A, A)); }

double Angle(const Vector& A)
{ return atan2(A.y, A.x); }

void GetCCIntersection(const Point& c1, double r1, const Point& c2, double r2, vector<double>& rad)
{
double d = Length(c1 - c2);
if(dcmp(d) == 0) return;
if(dcmp(d-r1-r2) > 0) return;
if(dcmp(d-fabs(r1-r2)) < 0) return;

double base = Angle(c2 - c1);
double ang = acos((r1*r1 + d*d - r2*r2) / (2.0*r1*d));
rad.push_back(NormalizeAngle(base + ang));
rad.push_back(NormalizeAngle(base - ang));
}

int n;

bool isVisible(const Point& C, int id)
{
for(int i = id + 1; i < n; ++i)
{
double d = Length(C - p[i]);
if(dcmp(d - radius[i]) <= 0) return false;    //这道题的关键所在
}
return true;
}

int main(void)
{
//freopen("10969in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i = 0; i < n; ++i) scanf("%lf%lf%lf", &radius[i], &p[i].x, &p[i].y);

double sum = 0.0;
for(int i = 0; i < n; ++i)
{
vector<double> rad;
rad.push_back(0.0);
rad.push_back(TWO_PI);
for(int j = 0; j < n; ++j)
{
if(j == i) continue;
GetCCIntersection(p[i], radius[i], p[j], radius[j], rad);
}
sort(rad.begin(), rad.end());

for(int j = 0; j < rad.size() - 1; ++j)
{
double mid = (rad[j] + rad[j + 1]) / 2;
double ang = rad[j + 1] - rad[j];
Point C(p[i].x + radius[i]*cos(mid), p[i].y + radius[i]*sin(mid));
if(isVisible(C, i)) sum += radius[i] * ang;
}
}

printf("%.3f\n", sum);
}

return 0;
}


代码君
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: