【计算几何】 P1652 圆

188 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

题目描述

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

输入格式

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

第二行是 nn 个整数,表示 nn 个圆的 xx 坐标;

第三行是 nn 个整数,表示 nn 个圆的 yy 坐标;

第四行是 nn 个整数,表示 nn 个圆的半径 rr

第五行是四个整数 x1,y1,x2,y2x_1,y_1,x_2,y_2

输出格式

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

样例 #1

样例输入 #1

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

样例输出 #1

3

提示

【数据范围】
对于 100%100\% 的数据,1n501\le n \le 50x,y1000|x|,|y| \le 10001r10001 \le r \le 1000
保证圆之间没有公共点。

解题思路

计算几何入门题

只有点在园内才会需要穿过圆的边界,否则绕过去就可以了

判断点是否在圆内就是他到圆心的距离小于半径(在圆内

但是还有一种情况都在一个圆内

可以发现都在一个圆内和都在圆外面不用穿过

如果 (x1,y1)在圆内 xor (x2,y2)在圆内 总数+1

代码

 #include<bits/stdc++.h>
    using namespace std;
    double dis(int x1,int y1,int x2,int y2) {
        return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
    int main() {
        int x1,y1,x2,y2,ans=0;
        int y[105][3],n;
        cin>>n;
        for(int i=0;i<3;i++) //读入
            for(int j=0;j<n;j++)
                cin>>y[j][i];
        cin>>x1>>y1>>x2>>y2;
        for(int i=0;i<n;i++)
            if(dis(x1,y1,y[i][0],y[i][1])<y[i][2]!=dis(x2,y2,y[i][0],y[i][1])<y[i][2]) ans++; //计入总数
        cout<<ans<<endl;  //输出
        return 0;
}