计算几何 - 圆 - 洛谷 P1652

计算几何 - 圆 - 洛谷 P1652

给 出 n 个 圆 , 保 证 任 意 两 个 圆 都 不 相 交 。 然 后 给 出 两 个 点 ( x 1 , y 1 ) , ( x 2 , y 2 ) , 保 证 均 不 在 某 个 圆 上 , 要 从 ( x 1 , y 1 ) − > ( x 2 , y 2 ) 画 条 曲 线 , 问 这 条 曲 线 最 少 穿 过 多 少 次 圆 的 边 界 ? 给出n个圆,保证任意两个圆都不相交。 然后给出两个点(x_1,y_1),(x_2,y_2),\\保证均不在某个圆上,要从(x_1,y_1)->(x_2,y_2)画条曲线,问这条曲线最少穿过多少次圆的边界? n,(x1,y1),(x2,y2)(x1,y1)>(x2,y2)线线穿

输入格式

第一行为一个整数 n,表示圆的个数;

第二行是 n 个整数,表示 n 个圆的 x 坐标;

第三行是 n 个整数,表示 n 个圆的 y 坐标;

第四行是 n 个整数,表示 n 个圆的半径 r;

第五行是四个整数 x 1 , y 1 , x 2 , y 2 x_1,y_1,x_2,y_2 x1,y1,x2,y2

输出格式

仅一个整数,表示最少要穿过多少次圆的边界。

输入输出样例

输入:

7
1 -3 2 5 -4 12 12
1 -1 2 5 5 1 1
8 1 2 1 1 1 2
-5 1 12 1

输出:

3

数据范围

对 于 100 % 的 数 据 , 1 ≤ n ≤ 50 , ∣ x ∣ , ∣ y ∣ ≤ 1000 , 1 ≤ r ≤ 1000 。 保 证 圆 之 间 没 有 公 共 点 。 对于 100\% 的数据,1\le n \le 50,|x|,|y| \le 1000,1 \le r \le1000。 保证圆之间没有公共点。 100%1n50x,y10001r1000


分析:

① 、 首 先 考 虑 特 殊 情 况 : ①、首先考虑特殊情况:

当 两 点 在 同 一 个 小 圆 内 部 或 者 两 个 点 都 未 被 任 何 圆 包 含 , 此 时 输 出 0. \qquad 当两点在同一个小圆内部或者两个点都未被任何圆包含,此时输出0. 0.

② 、 一 般 情 况 : ②、一般情况:

当 其 中 一 个 点 被 某 个 圆 包 围 时 , 我 们 可 将 整 个 圆 视 作 一 个 ′ ′ 大 点 ′ ′ , 如 下 图 \qquad 当其中一个点被某个圆包围时,我们可将整个圆视作一个''大点'',如下图
在这里插入图片描述

在 两 个 ′ ′ 大 点 ′ ′ 之 间 连 线 , 无 需 穿 过 任 何 边 界 , 在两个''大点''之间连线,无需穿过任何边界, 线穿

而 对 ′ ′ 小 点 ′ ′ A 而 言 , 至 少 穿 过 2 层 边 界 才 能 与 B 相 连 , 对 小 点 ′ ′ B ′ ′ 而 言 , 至 少 穿 过 1 层 边 界 才 能 与 A 相 连 。 而对''小点''A而言,至少穿过2层边界才能与B相连,对小点''B''而言,至少穿过1层边界才能与A相连。 A穿2BB穿1A

事 实 上 , 对 于 任 意 一 个 圆 , 若 A 、 B 两 点 在 该 圆 的 两 侧 , 则 至 少 要 穿 过 这 层 边 界 才 能 在 A 、 B 间 连 线 。 事实上,对于任意一个圆,若A、B两点在该圆的两侧,则至少要穿过这层边界才能在A、B间连线。 AB穿AB线

于 是 , 问 题 转 化 为 , 统 计 有 多 少 个 圆 , 将 A 、 B 两 点 划 分 在 圆 的 内 外 两 侧 。 于是,问题转化为,统计有多少个圆,将A、B两点划分在圆的内外两侧。 AB

我 们 仅 需 保 证 , 一 个 点 到 圆 心 的 距 离 小 于 半 径 , 另 一 个 点 到 圆 心 的 距 离 大 于 半 径 , 即 可 满 足 条 件 。 我们仅需保证,一个点到圆心的距离小于半径,另一个点到圆心的距离大于半径,即可满足条件。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;

const int N=55;

struct Point
{
    double x,y,r;
}V[N];

int n;
Point a,b;

double get_dis(Point a,Point b) //两点之间的距离
{
    double dx=a.x-b.x, dy=a.y-b.y;
    return sqrt(dx*dx+dy*dy);
}

int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>V[i].x;
    for(int i=0;i<n;i++) cin>>V[i].y;
    for(int i=0;i<n;i++) cin>>V[i].r;
    cin>>a.x>>a.y>>b.x>>b.y;
    
    int cnt=0;
    for(int i=0;i<n;i++)
        if((get_dis(a,V[i])<V[i].r) ^ (get_dis(b,V[i])<V[i].r)) cnt++;
    
    cout<<cnt<<endl;
    
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值