poj 1418 Viva Confetti(计算几何,圆)

题意:每次有n个圆盘,给出每个圆盘的圆心坐标及半径,问最后有几个圆盘可见;

参考:http://blog.csdn.net/tenlee/article/details/40380599

思路:大白书上的例题。对于每个圆求与其他圆的交点,看两交点围成的弧的中点是否被覆盖,统计未被覆盖的点数(部分思路);

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

const int  MAX_N = 128;
const double EPS = 5e-13;
const double PI = acos(-1.0);

typedef struct
{
    double x, y;
} point;

//两点距离
double Distance(const point & p1, const point & p2);

//如果一个角大于360,减去360,小于0加上360
double MainAngle(double a);

int  n;    //number of circles
point o[MAX_N];  //圆心
double r[MAX_N];  //圆的弧度

int  pan;   //与这个圆的交点数目
double pa[2 * MAX_N]; //存放与这个圆所有交点对应的弧度
int  visible[MAX_N]; //是否被访问过
int  ans;   //answer

int main()
{

    int i, j, k, t;
    point tp;
    double a, b, d;
    while (scanf("%d", &n), n)
    {
        for (i = 0; i < n; ++i)
        {
            scanf("%lf %lf %lf", &o[i].x, &o[i].y, &r[i]);
            visible[i] = 0;
        }

        for (i = 0; i < n; ++i)
        {
            pan = 0;
            pa[pan++] = 0;
            pa[pan++] = 2 * PI;

            for (j = 0; j < n; ++j)
            {
                if (j == i)
                {
                    continue;
                }

                d = Distance(o[i], o[j]); //判断两个圆心距离

                if (r[i] + r[j] < d || r[i] + d < r[j] || r[j] + d < r[i]) //包含或不相交的
                {
                    continue;
                }

                a = atan2(o[j].y - o[i].y, o[j].x - o[i].x);//atan2(),是求这个点和x轴正方形夹角,*PI/180  得到度数
                b = acos((r[i] * r[i] + d * d - r[j] * r[j]) / (2 * r[i] * d));

                pa[pan] = MainAngle(a + b);
                pan++;
                pa[pan] = MainAngle(a - b);
                pan++;
            }

            sort(pa, pa + pan);

            for (j = 0; j < pan - 1; ++j)
            {
                a = (pa[j] + pa[j + 1]) / 2;

                for (t = -1; t < 2; t += 2) //t = -1 或 1
                {
                    //将每段圆弧中点往内外各移动很小距离
                    tp.x = o[i].x + (r[i] + t * EPS) * cos(a);
                    tp.y = o[i].y + (r[i] + t * EPS) * sin(a);

                    for (k = n - 1; k >= 0; --k)
                    {
                        //如果找到第一个cover point i 的 Arc j 的圆,break
                        if (Distance(tp, o[k]) < r[k])
                        {
                            break;
                        }
                    }
                    visible[k] = 1;
                }
            }
        }

        ans = 0;

        for (i = 0; i < n; ++i)
            if (visible[i] == 1)
            {
                ans++;
            }

        printf("%d\n", ans);
    }

    return 0;
}



double Distance(const point & p1, const point & p2)
{
    return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}



double MainAngle(double a)
{
    while (a > 2 * PI)
    {
        a -= 2 * PI;
    }
    while (a < 0)
    {
        a += 2 * PI;
    }

    return a;
}

 

posted on 2015-11-08 22:35  大树置林  阅读(336)  评论(0编辑  收藏  举报

导航