搜索题目整理

搜索题目整理

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
");
			continue;
		}
			for(ll i=1;i<=n;i++)
				if(nd[i].z-r<=0)
					if(search(i)){
						ok=1;
						printf("Yes
");
						break;
					}
			if(!ok)
				printf("No
");
	}return 0;
}
原文地址:https://www.cnblogs.com/648-233/p/12726320.html