本文将同步发布于:

题目

题目链接:洛谷 P3428官网

题意简述

给定 \(n\) 个圆 \((x_i,y_i,r_i)\),每个圆对应一个点集 \(S_i=\left\{(x,y)\mid (x-x_i)^2+(y-y_i)^2\leq r_i^2\right\}\)。

求一个最小的 \(i\) 满足 \(\cap_{j=1}^i S_j=\varnothing\);如果无解输出 NIE

题解

简单又自然的随机化

我们考虑枚举 \(i\),然后判定 \(S_{1\sim i}\) 的交集是否为空。

如何判定呢?我们想到一个简单的方法,我们随机一些在圆的边界上的点,只需要判定这些点是否存至少在一个点在所有圆内即可。

这种方法简单又自然,但是随机化算法正确率不高,这远远不够。

研究几何性质

如果做计算几何题而抛弃几何性质,所得到的做法往往是劣解。

继续沿着上面的思路,我们同样考虑枚举 \(i\),然后判定 \(S_{1\sim i}\) 的交集是否为空。

不同的是,我们定义一个交集中横坐标最大的点为代表点(代表点只会有一个,这是因为圆是凸集,凸集的交集还是凸集)。

我们发现,如果一些圆的交集非空,那么其代表点一定满足:它是所有圆两两交集的代表中横坐标最小的那个。

证明十分显然,考虑交集的意义即可。

最后的结论

综上所述,对于一个 \(i\),我们只需要求出 \(1\sim i-1\) 与 \(i\) 的代表点即可,如果所有代表点中横坐标最小的那一个在所有的圆内,那么其合法,否则不合法,换言之,答案为 \(i\)。

我们考虑证明这个结论:

  • 若没有交集,则这个点必然不合法,符合我们的预期;
  • 若有交集,则我们需要证明这个点是交集的代表点。
    • 假设其不是交集的代表点,则交集的代表点可能在其左右;
    • 左边:不可能,若交集存在,则代表点的横坐标 \(\geq\) 当前点横坐标。
    • 右边:不可能,考虑当前点在 \(S_a\cap S_b\) 中得到,那么所有 \(x\geq\) 当前点横坐标的点均被交集抛弃,因此代表点的横坐标 \(\leq\) 当前点横坐标。
    • 由夹逼过程可知结论正确。

这个算法的时间复杂度为 \(\Theta(n^2)\)。

参考程序

下面我们来解决两圆求交的问题。

下面介绍一下两种方法:余弦定理和相似三角形。

余弦定理

用余弦定理求解需要用到三角函数,常数大,精度差。

我们考虑下图:

对 \(\triangle{ACB}\) 运用余弦定理,得到 \(r_a^2+d^2-2dr_a\cos\alpha=r_b^2\),进而求出 \(\alpha=\arccos\left(\frac{r_a^2+d^2-r_b2}{2dr_a}\right)\)。

然后我们再求出基准角 \(\beta\),显然 \(\beta=\texttt{atan2}(y_b-y_a,x_b-x_a)\)。

因此,我们得到了 \(C,D\) 两点的对 \(A\) 的极角为 \(\beta+\alpha\),\(\beta-\alpha\)。

对于极角为 \(\theta\),极径为 \(r_a\) 的点,我们得出其对应点的坐标为 \((r_a\cos\theta,r_a\sin\theta)\)。

#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll; const double eps=1e-6; inline int sgn(reg double x){
if(fabs(x)<eps)
return 0;
else
return x<0?-1:1;
} inline double sqr(reg double x){
return x*x;
} const int MAXN=2e3+5; struct Vector{
double x,y;
inline Vector(reg double x=0,reg double y=0):x(x),y(y){
return;
}
inline Vector operator+(const Vector& a)const{
return Vector(x+a.x,y+a.y);
}
inline Vector operator-(const Vector& a)const{
return Vector(x-a.x,y-a.y);
}
inline Vector operator*(const double a)const{
return Vector(x*a,y*a);
}
}; inline double dot(const Vector& a,const Vector& b){
return a.x*b.x+a.y*b.y;
} inline double cross(const Vector& a,const Vector& b){
return a.x*b.y-a.y*b.x;
} typedef Vector Point; inline double getDis2(const Point& a,const Point& b){
return dot(a-b,a-b);
} inline double getDis(const Point& a,const Point& b){
return sqrt(getDis2(a,b));
} inline bool isEmpty(const Point& a){
return a.x!=a.x||a.y!=a.y;
} struct Circle{
Point o;
double r;
inline bool contain(const Point& x)const{
return sgn(sqr(r)-getDis2(x,o))>=0;
}
inline Point getRig(void)const{
return o+Vector(r,0);
}
}; inline bool isCon(const Circle& a,const Circle& b){
return sgn(sqr(a.r-b.r)-getDis2(a.o,b.o))>=0;
} inline bool isSep(const Circle& a,const Circle& b){
return sgn(getDis2(a.o,b.o)-sqr(a.r+b.r))>0;
} inline Point getPot(const Circle &a,const Circle &b){
if(isCon(a,b))
if(sgn(b.getRig().x-a.getRig().x)>0)
return a.getRig();
else
return b.getRig();
else if(isSep(a,b))
return Point(nan(""),nan(""));
else{
if(a.contain(b.getRig()))
return b.getRig();
else if(b.contain(a.getRig()))
return a.getRig();
else{
reg double d=getDis(a.o,b.o);
reg double ang=acos(((sqr(a.r)+sqr(d))-sqr(b.r))/(2*a.r*d));
reg double delta=atan2(b.o.y-a.o.y,b.o.x-a.o.x);
reg double ang1=delta+ang,ang2=delta-ang;
Point p1=a.o+Vector(cos(ang1)*a.r,sin(ang1)*a.r);
Point p2=a.o+Vector(cos(ang2)*a.r,sin(ang2)*a.r);
Point res;
if(sgn(p2.x-p1.x)>0)
res=p2;
else
res=p1;
return res;
}
}
} int n;
Circle a[MAXN]; int main(void){
scanf("%d",&n);
Point lef(0,0);
for(reg int i=1;i<=n;++i){
static int x,y,r;
scanf("%d%d%d",&x,&y,&r);
a[i].o=Point(x,y),a[i].r=r;
if(i==2)
lef=getPot(a[1],a[2]);
else if(i>2){
for(reg int j=1;j<i&&!isEmpty(lef);++j){
Point tmp=getPot(a[i],a[j]);
if(isEmpty(tmp)||tmp.x<=lef.x)
lef=tmp;
}
for(reg int j=1;j<=i&&!isEmpty(lef);++j)
if(!a[j].contain(lef))
lef=Point(nan(""),nan(""));
}
if(isEmpty(lef)){
printf("%d\n",i);
return 0;
}
}
puts("NIE");
return 0;
}

相似三角形

如上图,我们设 \(a=|AG|\),\(b=|BG|\),\(h=|CG|\)。

那么我们有:

\[\begin{cases}r_a^2=a^2+h^2\\r_b^2=b^2+h^2\\a+b=d\end{cases}
\]

那么我们有:

\[a=\frac{r_a^2+d^2-r_b^2}{2d}
\]

然后考虑 \(\triangle AIB\sim\triangle CHG\),我们有:

\[(y_b-y_a)h=d(y_c-y_g)
\]

我们可由此解出坐标,其他同理可算出。

#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll; const double eps=1e-6; inline int sgn(reg double x){
if(fabs(x)<eps)
return 0;
else
return x<0?-1:1;
} inline double sqr(reg double x){
return x*x;
} const int MAXN=2e3+5; struct Vector{
double x,y;
inline Vector(reg double x=0,reg double y=0):x(x),y(y){
return;
}
inline Vector operator+(const Vector& a)const{
return Vector(x+a.x,y+a.y);
}
inline Vector operator-(const Vector& a)const{
return Vector(x-a.x,y-a.y);
}
inline Vector operator*(const double a)const{
return Vector(x*a,y*a);
}
}; inline double dot(const Vector& a,const Vector& b){
return a.x*b.x+a.y*b.y;
} inline double cross(const Vector& a,const Vector& b){
return a.x*b.y-a.y*b.x;
} typedef Vector Point; inline double getDis2(const Point& a,const Point& b){
return dot(a-b,a-b);
} inline double getDis(const Point& a,const Point& b){
return sqrt(getDis2(a,b));
} inline bool isEmpty(const Point& a){
return isnan(a.x)||isnan(a.y);
} struct Circle{
Point o;
double r;
inline bool contain(const Point& x)const{
return sgn(sqr(r)-getDis2(x,o))>=0;
}
inline Point getRig(void)const{
return o+Vector(r,0);
}
}; inline bool isCon(const Circle& a,const Circle& b){
return sgn(sqr(a.r-b.r)-getDis2(a.o,b.o))>=0;
} inline bool isSep(const Circle& a,const Circle& b){
return sgn(getDis2(a.o,b.o)-sqr(a.r+b.r))>0;
} inline Point getPot(const Circle &a,const Circle &b){
if(isCon(a,b))
if(sgn(b.getRig().x-a.getRig().x)>0)
return a.getRig();
else
return b.getRig();
else if(isSep(a,b))
return Point(nan(""),nan(""));
else{
if(a.contain(b.getRig()))
return b.getRig();
else if(b.contain(a.getRig()))
return a.getRig();
else{
reg double d=getDis(a.o,b.o);
reg double val=(sqr(a.r)+sqr(d)-sqr(b.r))/(2*d);
reg double h=sqrt(sqr(a.r)-sqr(val));
Point bas=a.o+(b.o-a.o)*(val/d);
Vector tmp=Vector(b.o.y-a.o.y,a.o.x-b.o.x)*(h/d);
Point p1=bas-tmp,p2=bas+tmp;
if(sgn(p2.x-p1.x)>0)
return p2;
else
return p1;
}
}
} int n;
Circle a[MAXN]; int main(void){
scanf("%d",&n);
Point lef(0,0);
for(reg int i=1;i<=n;++i){
static int x,y,r;
scanf("%d%d%d",&x,&y,&r);
a[i].o=Point(x,y),a[i].r=r;
if(i==2)
lef=getPot(a[1],a[2]);
else if(i>2){
for(reg int j=1;j<i&&!isEmpty(lef);++j){
Point tmp=getPot(a[i],a[j]);
if(isEmpty(tmp)||tmp.x<=lef.x)
lef=tmp;
}
for(reg int j=1;j<=i&&!isEmpty(lef);++j)
if(!a[j].contain(lef))
lef=Point(nan(""),nan(""));
}
if(isEmpty(lef)){
printf("%d\n",i);
return 0;
}
}
puts("NIE");
return 0;
}

「题解」POI2005 AKC-Special Forces Manoeuvres的更多相关文章

  1. 「题解」「HNOI2013」切糕

    文章目录 「题解」「HNOI2013」切糕 题目描述 思路分析及代码 题目分析 题解及代码 「题解」「HNOI2013」切糕 题目描述 点这里 思路分析及代码 题目分析 这道题的题目可以说得上是史上最 ...

  2. 「题解」「美团 CodeM 资格赛」跳格子

    目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...

  3. 「题解」JOIOI 王国

    「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...

  4. 「题解」:[loj2763][JOI2013]现代豪宅

    问题 A: 现代豪宅 时间限制: 1 Sec  内存限制: 256 MB 题面 题目描述 (题目译自 $JOI 2013 Final T3$「現代的な屋敷」) 你在某个很大的豪宅里迷路了.这个豪宅由东 ...

  5. 「题解」:$Six$

    问题 A: Six 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 来写一篇正经的题解. 每一个数对于答案的贡献与数本身无关,只与它包含了哪几个质因数有关. 所以考虑二 ...

  6. 「题解」:$Smooth$

    问题 A: Smooth 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 维护一个队列,开15个指针,对应前15个素数. 对于每一次添加数字,暴扫15个指针,将指针对应 ...

  7. 「题解」:Kill

    问题 A: Kill 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 80%算法 赛时并没有想到正解,而是选择了另一种正确性较对的贪心验证. 对于每一个怪,我们定义它的 ...

  8. 「题解」:y

    问题 B: y 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 考虑双向搜索. 定义$cal_{i,j,k}$表示当前已经搜索状态中是否存在长度为i,终点为j,搜索过边 ...

  9. 「题解」:x

    问题 A: x 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 赛时想到了正解并且对拍了很久.对拍没挂,但是评测姬表示我w0了……一脸懵逼. 不难证明,如果对于两个数字 ...

随机推荐

  1. UVA10943简单递推

    题意:      给你两个数字n,k,意思是用k个不大于n的数字组合(相加和)为n一共有多少种方法? 思路:       比较简单的递推题目,d[i][j]表示用了i个数字的和为j一共有多少种情况,则 ...

  2. 神经网络与机器学习 笔记—卷积神经网络(CNN)

    卷积神经网络 之前的一些都是考虑多层感知器算法设计相关的问题,这次是说一个多层感知器结构布局相关的问题.来总结卷积神经网络.对于模式分类非常合适.网络的提出所隐含的思想收到了神经生物学的启发. 第一个 ...

  3. 如何在jQuery的Ajax调用后管理一个重定向请求

    1 success:function(data){ 2 if(data.xx == "xx") 3 { 4 //code... 5 window.location.href =&q ...

  4. <JVM上篇:内存与垃圾回收篇>04-虚拟机栈

    笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...

  5. thymeleaf中[[${}]]与[(${})]的区别

    [[-]]会被转义,[(-)]不会. 假设在后台传入msg的值为 <b>AAA</b> 在前台这样使用 [[${msg}]]___[(${msg})] 展示效果 官方参考文档

  6. 【maven】理论知识

    Maven是跨平台的项目管理工具,主要服务于Java平台的项目构建.依赖管理. 项目构建 项目构建过程包括[清理项目]→[编译项目]→[测试项目]→[生成测试报告]→[打包项目]→[部署项目]这几个步 ...

  7. WTM Blazor,Blazor开发利器

    Blazor从诞生到现在也有一段时间了,之前一直在观望,从dotnet5中Blazor的进步以及即将到来的dotnet6中的规划来看,Blazor的前途还是光明的,所以WtmBlazor来了! Bla ...

  8. Spring Security + OAuth2 + JWT 基本使用

    Spring Security + OAuth2 + JWT 基本使用 前面学习了 Spring Security 入门,现在搭配 oauth2 + JWT 进行测试. 1.什么是 OAuth2 OA ...

  9. 【近取 Key】Alpha - v1.0 版本发布说明

    功能与特性 Alpha 版本虽然为本软件的第一代版本,但已基本覆盖了用户个人使用时的主要功能.除登陆注册与后台管理外,下文将分版块详细介绍面向用户的主要功能特性. 『产品主页』 潜在应用场景 场景 0 ...

  10. 『动善时』JMeter基础 — 17、JMeter配置元件【HTTP请求默认值】

    目录 1.HTTP请求默认值介绍 2.HTTP请求默认值界面 3.HTTP请求默认值的使用 (1)用于演示的项目说明 (2)测试计划内包含的元件 (3)说明HTTP请求默认值用法 4.总结 5.拓展知 ...