@AkamemakA
2022-07-11T13:46:26.000000Z
字数 1680
阅读 201
Atcoder 题解
题目链接:点我
在平面直角坐标系中给定个圆,第个圆的圆心坐标为,半径为。给定两个坐标,问能否从点通过这些圆的圆周走到点。
对于每个测试点,第一行输入,第二行输入,其后行,每行输入。
如果能到达,输出"Yes";否则输出"No"。
40 -2 3 30 0 22 0 22 3 1-3 3 3
Yes

下面是一种从走到的方法:
30 1 0 30 0 10 0 20 0 3
No

这种情况下是不可能达到的。所以输出"No"。
乍一看,这个题仿佛没什么思路。
不过仔细思考一下,就可以发现:如果我们将所有圆编号并看做一个点,那么从一个圆的圆周能走到另一个圆的圆周,就是等价于能从这个点走到那个点。
于是,我们双层枚举所有圆,判断两个圆之间是否相交。如果相交,那么两点之间就有一条边。判断完后,就可以一遍简单的深搜找到所在的圆能否到达所在的圆。
起点与终点可能会位于多个圆上,不过这并没有影响。只需要找到其中一个圆即可。
#include<bits/stdc++.h>using namespace std;#define int long longconst int N=3005;int n;int sx,sy,tx,ty;int x[N],y[N],r[N];vector<int> v[N]; //邻接矩阵bool vis[N];int s,t;inline bool dfs(int s){vis[s]=1;if(s==t) return 1;for(int i=0;i<v[s].size();i++){if(vis[v[s][i]])continue;if(dfs(v[s][i])) return 1;}return 0;}signed main(){cin>>n;cin>>sx>>sy>>tx>>ty;for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&x[i],&y[i],&r[i]);for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++){int d=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); //d为两圆心之间的距离 的平方if(d>(r[i]+r[j])*(r[i]+r[j]) || d<(r[i]-r[j])*(r[i]-r[j])) continue;//如果圆心距大于两圆半径之和,则两圆相离,这种情况下两圆无法相互到达;//如果圆心距小于两圆半径之差,则大圆包含着小圆,这种情况下两圆也无法相互到达;v[i].push_back(j);v[j].push_back(i);//如果可以相互到达,则点i与点j有双向边。}for(int i=1;i<=n;i++){if((x[i]-sx)*(x[i]-sx)+(y[i]-sy)*(y[i]-sy)==r[i]*r[i]) s=i;if((x[i]-tx)*(x[i]-tx)+(y[i]-ty)*(y[i]-ty)==r[i]*r[i]) t=i;}//找到起点与终点所在圆的编号if(dfs(s)) cout<<"Yes"; //小dfs一下~else cout<<"No";return 0;}
完结撒花~