POJ 1418 Viva Confetti(Japan 2002 Kanazawa)

来源:互联网 发布:奶牛去广告软件 编辑:程序博客网 时间:2024/05/01 08:02

点击打开链接

算法竞赛入门经典--训练指南

题目大意:n个圆盘依次放在桌面上,给出每个圆盘的坐标和圆心,求能看见的圆的个数;

分析:圆的每个可见部分由小圆弧围成,因此可以先求出所有小圆弧,然后判断每段小圆弧内外两侧的可见圆盘.具体来说,把小圆弧中点往内外两侧各移动很小距离,得到两个点,然后标记包含这两个点的圆盘中最顶部的那个为可见的;

算法实现:离散化求出与一个圆的所有交点的弧度,排序后, 两个相邻的交点之间 只有 一个 弧,在求这个弧的中点,分别向内外移动,判断

CODE:

#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加上360double MainAngle(double a);int  n;    //number of circlespoint o[MAX_N];  //圆心double r[MAX_N];  //圆的弧度int  pan;   //与这个圆的交点数目double pa[2 * MAX_N]; //存放与这个圆所有交点对应的弧度int  visible[MAX_N]; //是否被访问过int  ans;   //answerint 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 的圆,breakif (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;}


0 1