搜索题目整理
搜索题目整理
T1:奶酪
现有一块大奶酪,它的高度为 \(h\),它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系,在坐标系中, 奶酪的下表面为\(z = 0\),奶酪的上表面为\(z = h\)。
现在,奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐标。如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别地,如果一个空洞与下表面相切或是相交,Jerry 则可以从奶酪下表面跑进空洞;如果一个空洞与上表面相切或是相交,Jerry 则可以从空洞跑到奶酪上表面。
位于奶酪下表面的 Jerry 想知道,在不破坏奶酪的情况下,能否利用已有的空洞跑到奶酪的上表面去?
空间内两点\(P_1(x_1,y_1,z_1)\)、\(P_2(x_2,y_2,z_2)\)的距离公式如下:
\(\mathrm{dist}(P_1,P_2)=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2}\)
思路
这道题数据范围较小,深搜或广搜都可以
在这里我用的深搜
需要注意的是数据要开\(long long\),以及\(double\)
当然,如果光是搜索是不行的,我们需要剪枝
这对这个题目可以发现,我们如果在考虑每一个洞的时候把其他所有洞都枚举一边,显然是会T的
如果这样能过的话,为什么不直接用并查集呢
所以我们将洞的坐标排序,洞的坐标一旦保证有序,枚举起来就极大地方便了,快捷了
代码
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define ll long long
using namespace std;
struct node{
ll x,y,z;
}nd[1005];
ll n,h,r,t;
inline double dis(const ll &l,const ll &r){
return sqrt((nd[l].x-nd[r].x)*(nd[l].x-nd[r].x)+(nd[l].y-nd[r].y)*(nd[l].y-nd[r].y)+(nd[l].z-nd[r].z)*(nd[l].z-nd[r].z));
}
bool vis[1005];
ll top;
ll bot;
inline bool search(const ll &k){
if(nd[k].z+r>=h) return 1;
for(ll i=1;i<=n;i++){
if(dis(k,i)<=r*2&&!vis[i]){
vis[i]=1;
if(search(i)) return 1;
}
}return 0;
}
inline bool cmp(const node &l,const node &r){
return l.z<r.z;
}
int main(){
scanf("%d",&t);
while(t--){
memset(nd,0,sizeof nd);
memset(vis,0,sizeof vis);
top=0;
bot=0;
scanf("%d%d%d",&n,&h,&r);
for(ll i=1;i<=n;i++){
scanf("%d%d%d",&nd[i].x,&nd[i].y,&nd[i].z);
if(nd[i].z-r<=0) bot++;
if(nd[i].z+r>=h) top++;
}
sort(nd+1,nd+1+n,cmp);
bool ok=0;
if(!bot){
printf("No\n");
continue;
}
for(ll i=1;i<=n;i++)
if(nd[i].z-r<=0)
if(search(i)){
ok=1;
printf("Yes\n");
break;
}
if(!ok)
printf("No\n");
}return 0;
}