题目大意

按照从底至顶的顺序给出平面上的 n n个圆(xi,yi,ri)(x_i,y_i,r_i),求从最顶上看能看到多少个圆。
一个测试点多组数据。

1≤n≤100,|xi|,|yi|∈[−10,10] 1\le n\le 100,|x_i|,|y_i|\in[-10,10]


题目分析

考虑扫描线,所有关键的横坐标是圆的左右两端以及任意两圆交点横坐标。这样每个区间内的圆都是完全跨越的,于是一个圆可见当且仅当其在某一个区间可见。
怎么判断一个圆在某个 x x坐标区间的可见性呢?显然我们取区间中任意一个xx坐标做一条竖直线(我取的是中点),然后求出所有跨立该区间的圆在这个条直线上交的区间,问题就可以转化成一个一维的区间可见性问题,我是离散化之后用并查集做的。
时间复杂度 O(n3(logn+α(n))) \mathrm O(n^3(\log_n+\alpha(n)))。


代码实现

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>using namespace std;typedef long double db;const db EPS=1e-8;
const int N=105;
const int M=N<<1;
const int L=N*N+N<<1;bool equ(db x,db y){return fabs(x-y)<EPS;}
int sgn(db x){return equ(x,0.0)?0:(x<0?-1:1);}
db sqr(db x){return x*x;}struct P
{db x,y;P (db x_=0.,db y_=0.){x=x_,y=y_;}P operator+(P const p)const{return P(x+p.x,y+p.y);}P operator-(P const p)const{return P(x-p.x,y-p.y);}P operator*(db k)const{return P(x*k,y*k);}db operator*(P const p)const{return x*p.x+y*p.y;}db operator^(P const p)const{return x*p.y-y*p.x;}
};db mod2(P p){return p*p;}
db mod(P p){return sqrt(mod2(p));}
db dist(P p,P q){return mod(q-p);}P rotate(P p,db a){return P(p.x*cos(a)-p.y*sin(a),p.x*sin(a)+p.y*cos(a));}
P adjust(P p,db len){return p*(len/mod(p));}struct C
{P O;db r;C (){}C (P O_,db r_=0.){O=O_,r=r_;}
}cir[N];void ict(C c,db x,P &p,P &q)
{if (x==c.O.x) p=P(x,c.O.y+c.r),q=P(x,c.O.y-c.r);else p=adjust(P(x-c.O.x,0),c.r),x=acos(fabs(x-c.O.x)/c.r),q=c.O+rotate(p,x),p=c.O+rotate(p,-x);
}bool is_intersectant(C c1,C c2)
{db d=dist(c1.O,c2.O);return sgn(c1.r+c2.r-d)>=0&&sgn(c1.r+d-c2.r)>0&&sgn(c2.r+d-c1.r)>0;
}
void ict(C c1,C c2,P &p,P &q)
{db d=dist(c1.O,c2.O),a=acos((sqr(c1.r)+sqr(d)-sqr(c2.r))/(2.*c1.r*d));p=adjust(c2.O-c1.O,c1.r),q=c1.O+rotate(p,a),p=c1.O+rotate(p,-a);
}struct data
{bool side;db key;int id;data (db key_=0.,int id_=0,bool side_=0){key=key_,id=id_,side=side_;}bool operator<(data const x)const{return key<x.key;}
}srt[M];struct range
{int l,r,h;bool operator<(range const x)const{return h<x.h;}
}rg[N];int fa[M],rgt[M],rank[M];
bool insight[N];
db tmp[N][2];
db line[L];
int n,ans,cnt,tot,rgs,num;void pre()
{cnt=0;for (int i=1;i<=n;++i){line[++cnt]=cir[i].O.x-cir[i].r,line[++cnt]=cir[i].O.x+cir[i].r;for (int j=i+1;j<=n;++j)if (is_intersectant(cir[i],cir[j])){P p,q;ict(cir[i],cir[j],p,q);line[++cnt]=p.x,line[++cnt]=q.x;}}sort(line+1,line+1+cnt);
}int getfather(int son){return fa[son]==son?son:fa[son]=getfather(fa[son]);}void merge(int x,int y,int r)
{if (rank[x]>rank[y]) swap(x,y);fa[x]=y,rank[y]+=rank[x]==rank[y],rgt[y]=r;
}void calc()
{for (int i=1;i<=n;++i) insight[i]=0;for (int i=2;i<=cnt;++i){tot=0;db lx=(line[i]+line[i-1])*.5;for (int j=1;j<=n;++j)if (sgn(cir[j].r-fabs(lx-cir[j].O.x))>=0){P p,q;ict(cir[j],lx,p,q);if (p.y>q.y) swap(p,q);rg[++tot].h=j,tmp[tot][0]=p.y,tmp[tot][1]=q.y;}rgs=0;for (int j=1;j<=tot;++j) srt[++rgs]=data(tmp[j][0],j,0),srt[++rgs]=data(tmp[j][1],j,1);sort(srt+1,srt+1+rgs);num=0;for (int j=1;j<=rgs;++j){num+=(j==1||!equ(srt[j].key,srt[j-1].key));if (srt[j].side) rg[srt[j].id].r=num;else rg[srt[j].id].l=num;}sort(rg+1,rg+1+tot);for (int j=1;j<=num;++j) fa[j]=rgt[j]=j,rank[j]=0;for (int j=tot,k,l;j>=1;--j)for (k=rgt[getfather(rg[j].l)],l=rgt[getfather(rg[j].r)],insight[rg[j].h]|=k!=l;l=rgt[getfather(rg[j].r)],k!=l;merge(getfather(k),getfather(k+1),rgt[getfather(k+1)]),k=rgt[getfather(k)]);}for (int i=1;i<=n;++i) ans+=insight[i];
}int main()
{freopen("confetti.in","r",stdin),freopen("confetti.out","w",stdout);for (;scanf("%d",&n),n;){for (int i=1;i<=n;++i){double x,y,r;scanf("%lf%lf%lf",&x,&y,&r),cir[i]=C(P(x*1000000.,y*1000000.),r*1000000.);}ans=0,pre(),calc(),printf("%d\n",ans);}fclose(stdin),fclose(stdout);return 0;
}

[POJ1418]Viva Confetti相关推荐

  1. ZOJ 1696 Viva Confetti 计算几何

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

  2. Viva Confetti UVALive - 2572

    Viva Confetti UVALive - 2572 **离散化的思想,将每一个圆都分成一个个小圆弧 const int maxn = 100+10; Point center[maxn]; do ...

  3. POJ 1418 Viva Confetti 题解 《挑战程序设计竞赛》

    为什么80%的码农都做不了架构师?>>>    POJ 1418 Viva Confetti礼花:Confetti 是一些大小不一的彩色圆形纸片,人们在派对上.过节时便抛洒它们以示庆 ...

  4. LA 2572 Viva Confetti (Geometry.Circle)

    https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=problem_st ...

  5. Viva Confetti UVA - 1308

    思路:由于圆与圆相交的可见部分都是有圆弧组成的,枚举一个圆与其他圆的交点,对两交点所形成的圆弧,去判断该圆弧的中间点是否在其他圆内.若都不在,则证明该圆没有被完全遮住. #include <cs ...

  6. POJ 1418 Viva Confetti(Japan 2002 Kanazawa)

    点击打开链接 算法竞赛入门经典--训练指南 题目大意:n个圆盘依次放在桌面上,给出每个圆盘的坐标和圆心,求能看见的圆的个数; 分析:圆的每个可见部分由小圆弧围成,因此可以先求出所有小圆弧,然后判断每段 ...

  7. LA 2572 Viva Confetti 离散化 *

    题目地址:https://vjudge.net/problem/UVALive-2572 离散化:把每个圆看成是一段一段弧组成的 每个圆拿出来看一下,先求其上与其他所有圆的交点.每两个交点之间的那段弧 ...

  8. 《挑战程序设计竞赛(第2版)》习题册攻略

    本项目来源于GitHub 链接: 项目GitHub链接 1 前言 项目为<挑战程序设计竞赛(第2版)>习题册攻略,已完结.可配合书籍或笔记,系统学习算法. 题量:约200道,代码注释内含详 ...

  9. POJ前面的题目算法思路【转】

    1000 A+B Problem 送分题 49% 2005-5-7 1001 Exponentiation 高精度 85% 2005-5-7 1002 487-3279 n/a 90% 2005-5- ...

最新文章

  1. B-tree/B+tree/B*tree
  2. excel模糊匹配两列文字_Excel快速画出美观饼图
  3. 九九乘法表(js_javascript)
  4. 吉林白山:“五脏俱全”的智能WiFi路灯点亮智慧城市
  5. C++ —— C++程序编译的四个过程
  6. 使用Spring-hadoop小结
  7. bootstrap-table toolbar图标换文字_iPhone 也能随意换字体啦~
  8. HDFS分布式文件系统设计思想
  9. IntelliJ IDEA开发入门教程
  10. java guava_多线程(java和guava两种方式):
  11. html页面跨域提交数据,前端跨域的整理
  12. eclipse无线循环输出时,怎样关闭
  13. vb.net 教程 目录
  14. python将数据保存为pdf
  15. 【记录】读《你在天堂里遇见的五个人》有感
  16. Vue组件通信:父传子、子传父、跨组件通信
  17. 【Coursera】深度神经网络的改进:超参数调整、正则化和优化(更新中2023/04/12)
  18. 竣达技术丨电池巡检微信云监控系统
  19. 轻断食:正在横扫全球的瘦身革命
  20. ERNIE3.0多分类任务应用详细教程代码

热门文章

  1. 灵雀云第三期(2020-2021)传统行业云原生技术落地调研报告
  2. 氮化镓充电器哪家做得好_这颗国产器看似简单:每个氮化镓充电器都少不了
  3. leetcode数据库题库-178. 分数排名
  4. 机器视觉毕业设计 python车牌识别系统 - opencv 深度学习 机器学习
  5. linux find 命令实战用法
  6. 在 Android 手机上恢复出厂设置后恢复照片的 4 种简单方法(新方法)
  7. 《信号完整性揭秘》读书笔记
  8. Android自定义控件面试题,自定义View面试总结
  9. 用户运营都做些什么?你需要知道这些
  10. 【推荐】母婴电商公司LOGO如何设计?