思路:

小圆面是由小圆弧围成。那么找出每条小圆弧,如果小圆弧,在小圆弧中点上下左右进行微小位移的所得的点一定在一个小圆面内。

找到最后覆盖这个小点的圆一定是可见的。

圆上的点按照相邻依次排序的关键量为极角(0,2PI)

用中心点代替圆弧本身是否被圆覆盖

 #include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<memory.h>
#include<cstdlib>
#include<vector>
#define clc(a,b) memset(a,b,sizeof(a))
#define LL long long int
#define up(i,x,y) for(i=x;i<=y;i++)
#define w(a) while(a)
using namespace std;
const int inf=0x3f3f3f3f;
const int N = ;
const double eps = *1e-;
const double pi = acos(-); int dcmp(double x)
{
if(fabs(x) < eps) return ;
else return x < ? - : ;
} const double PI = acos(-);
const double TWO_PI = PI * ; double NormalizeAngle(double rad, double center = PI)
{
return rad - TWO_PI * floor((rad + PI - center) / TWO_PI);
} struct Point
{
double x, y;
Point(double x=, double y=):x(x),y(y) { }
}; typedef Point Vector; Vector operator + (Vector A, Vector B)
{
return Vector(A.x+B.x, A.y+B.y);
}
Vector operator - (Point A, Point B)
{
return Vector(A.x-B.x, A.y-B.y);
}
Vector operator * (Vector A, double p)
{
return Vector(A.x*p, A.y*p);
}
Vector operator / (Vector A, double p)
{
return Vector(A.x/p, A.y/p);
} double Dot(Vector A, Vector B)
{
return A.x*B.x + A.y*B.y;
}
double Length(Vector A)
{
return sqrt(Dot(A, A));
} double angle(Vector v)
{
return atan2(v.y, v.x);
} // 交点相对于圆1的极角保存在rad中
void getCircleCircleIntersection(Point c1, double r1, Point c2, double r2, vector<double>& rad)
{
double d = Length(c1 - c2);
if(dcmp(d) == ) return; // 不管是内含还是重合,都不相交
if(dcmp(r1 + r2 - d) < ) return;
if(dcmp(fabs(r1-r2) - d) > ) return; double a = angle(c2 - c1);
double da = acos((r1*r1 + d*d - r2*r2) / (*r1*d));
rad.push_back(NormalizeAngle(a-da));
rad.push_back(NormalizeAngle(a+da));
} const int maxn = + ;
int n;
Point center[maxn];
double radius[maxn];
bool vis[maxn]; // 覆盖点p的最上层的圆
int topmost(Point p)
{
for(int i = n-; i >= ; i--)
if(Length(center[i]-p) < radius[i]) return i;
return -;
} int main()
{
while(cin >> n)
{
if(!n) break;
for(int i = ; i < n; i++)
{
double x, y, r;
cin >> x >> y >> r;
center[i] = Point(x, y);
radius[i] = r;
}
memset(vis, , sizeof(vis));
for(int i = ; i < n; i++)
{
// 考虑圆i被切割成的各个圆弧。把圆周当做区间来处理,起点是0,终点是2PI
vector<double> rad;
rad.push_back();
rad.push_back(PI*);
for(int j = ; j < n; j++)
getCircleCircleIntersection(center[i], radius[i], center[j], radius[j], rad);
sort(rad.begin(), rad.end()); for(int j = ; j < rad.size(); j++)
{
double mid = (rad[j] + rad[j+]) / 2.0; // 圆弧中点相对于圆i圆心的极角
for(int side = -; side <= ; side += )
{
double r2 = radius[i] - side*eps; // 往里面或者外面稍微一动一点点
int t = topmost(Point(center[i].x + cos(mid)*r2, center[i].y + sin(mid)*r2));
if(t >= ) vis[t] = true;
}
}
}
int ans = ;
for(int i = ; i < n; i++) if(vis[i]) ans++;
cout << ans << "\n";
}
return ;
}

uva 2572 Viva Confetti的更多相关文章

  1. uva 1308 - Viva Confetti

    这个题目的方法是将圆盘分成一个个圆环,然后判断这些圆环是否被上面的圆覆盖: 如果这个圆的圆周上的圆弧都被上面的覆盖,暂时把它标记为不可见: 然后如果他的头上有个圆,他有个圆弧可见,那么他自己本身可见, ...

  2. poj1418 Viva Confetti 判断圆是否可见

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Viva Confetti Time Limit: 1000MS   Memory ...

  3. poj 1418 Viva Confetti

    Viva Confetti Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 1025   Accepted: 422 Desc ...

  4. ZOJ 1696 Viva Confetti 计算几何

    计算几何:按顺序给n个圆覆盖.问最后能够有几个圆被看见.. . 对每一个圆求和其它圆的交点,每两个交点之间就是可能被看到的圆弧,取圆弧的中点,往外扩展一点或者往里缩一点,从上往下推断有没有圆能够盖住这 ...

  5. UVaLive2572 poj1418 UVa1308 Viva Confetti

    一次放下n个圆 问最终可见的圆的数量 应该是比较经典的问题吧 考虑一个圆与其他每个圆的交点O(n)个 将其割成了O(n)条弧 那么看每条弧的中点 分别向内向外调动eps这个点 则最上面的覆盖这个点的圆 ...

  6. LA2572 Viva Confetti

    题意 PDF 分析 两两圆求交点,对每个圆弧按半径抖动. 时间复杂度\(O(T n^2)\) 代码 #include<iostream> #include<cstdio> #i ...

  7. [GodLove]Wine93 Tarining Round #9

    比赛链接: http://vjudge.net/contest/view.action?cid=48069#overview 题目来源: lrj训练指南---二维几何计算   ID Title Pro ...

  8. POJ 1418 基本操作和圆 离散弧

    Viva Confetti Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 761   Accepted: 319 Descr ...

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

    题意: 有n个按先后顺序放置的不同大小不同位置的圆,求所有可见圆弧的长度. 分析: 这道题应该是大白书上例题 LA 2572 (求可见圆盘的数量) Kanazawa 的加强版,整体框架都差不多. 对于 ...

随机推荐

  1. HIBERNATE一对一双向外键联合主键关联

    HIBERNATE一对一双向外键联合主键关联: 一. 创建主键类:这个主键必须实现serializedable接口和重写其中的hashCode方法和equals方法:为主键类添加一个叫做@Embedd ...

  2. 如何将word中上下两行文字对齐?

    一.问题来源及描述 本科毕设的时候积累的问题,整理如下. 红头文件下面的署名,上下要对齐. 二.解决办法 经验证,第一次拉标尺要把标尺放在第一行的光标处,为了换行后,再次enter,tab后到与上一行 ...

  3. 修改MYSQL数据库表的字符集

    MySQL 乱码的根源是的 MySQL 字符集设置不当的问题,本文汇总了有关查看 MySQL 字符集的命令.包括查看 MySQL 数据库服务器字符集.查看 MySQL 数据库字符集,以及数据表和字段的 ...

  4. linux命令补全 忘记命令只记得开头

    linux的shell不仅提供上下箭头来翻阅历史使用过的命令,还提供命令补全功能. 例如,你想创建一个文件夹,只记得是m开头的命令,此时可以: ①输入m ②按键盘上的Tab键两次 (有可能还出现这句话 ...

  5. C# Winform应用程序占用内存较大解决方法整理

     微软的 .NET FRAMEWORK 现在可谓如火如荼了.但是,.NET 一直所为人诟病的就是“胃口太大”,狂吃内存,虽然微软声称 GC 的功能和智能化都很高,但是内存的回收问题,一直存在困扰,尤其 ...

  6. 198. House Robber

    题目: You are a professional robber planning to rob houses along a street. Each house has a certain am ...

  7. 最短路径算法之一——Floyd算法

    Floyd算法 Floyd算法可以用来解决任意两个顶点之间的最短路径问题. 核心公式为: Edge[i][j]=Min{Edge[i][j],Edge[i][k]+Edge[k][j]}. 即通过对i ...

  8. Android EditText属性

    1.EditText输入的文字为密码形式的设置 (1)通过.xml里设置: 把该EditText设为:android:password="true" // 以”.”形式显示文本 ( ...

  9. c#自带压缩类实现数据库表导出到CSV压缩文件的方法

    在导出大量CSV数据的时候,常常体积较大,采用C#自带的压缩类,可以方便的实现该功能,并且压缩比例很高,该方法在我的开源工具DataPie中已经经过实践检验.我的上一篇博客<功能齐全.效率一流的 ...

  10. java socket nio编程

    上次写了一个socket的基本编程,但是有个问题,阻塞特别严重,于是小编便去找了nio学习了一下... public class TimeServer { public static void mai ...