人生第一篇题解,多多关照吧。
注意事项:
1.多组数据,每次要先初始化。
2.因为涉及到开根,所以记得开double。整体思路:
建图,判断「起点」与「终点」是否连通。
方法可选择搜索(我写的BFS)或并查集(UFS)。 首先,读入时记录这些球的最小高度和最大高度,如果最低的球与底面相离,或是最高的球与顶面相离,直接Pass。 我们会发现,可能不止一个球与底面相切或相交,也可能不止一个球与顶面相切或相交。 这就是说,起点和终点都可能不止一个,这给我们操作造成了一些麻烦(然而考场上我就这么硬搜的居然AC了)。 其实,通过建立「超级起点」和「超级终点」,可以把操作变得简单——用结构体数组的第0个元素表示「超级起点」,第n+1个元素表示「超级终点」。两种方法都需要进行的预处理操作:
对于每一组球(i,j),计算两球球心距离是否小于半径×2。
走一遍所有的球,如果当前球可以做起点,就连上当前球和超级起点;终点亦然。方法1——BFS:
用二维bool数组e[i][j]记录i能否到达j,相当于存图(链式前向星也可以的,只是本题数据范围没有必要)。
对于每一个球,依次判断其能否到达0..n+1,当「超级终点」已被访问或队列已为空时结束搜索。 如果「超级终点」被访问过说明搜到了,可以到达;否则无法到达。#include#include #include #include #include using namespace std;const int MAXN=1010;bool vis[MAXN],e[MAXN][MAXN];double h,r,low,high;int T,n;struct ball{ double x,y,z;}s[MAXN];double dis(ball a,ball b){ double t1=a.x-b.x,t2=a.y-b.y,t3=a.z-b.z; return sqrt(t1*t1+t2*t2+t3*t3);}void Init()//一定记得初始化{ low=h,high=0; memset(vis,0,sizeof vis); memset(e,0,sizeof e);}void Pre()//预处理{ for(int i=1;i<=n;++i) { if(s[i].z-r<=0)//超级起点 e[0][i]=e[i][0]=1; if(s[i].z+r>=h)//超级终点 e[n+1][i]=e[i][n+1]=1; } for(int i=1;i