超级水的并没有用什么几何知识的几何题……
直接爆搜一遍最后判断有没有与上/下表面相连的球之间连通即可……O(n2)不动脑子的复杂度
最多只是用一下并查集来判断两个点是否连通……
具体细节不必赘述代码如下(超简洁只有51行)
1 #include<cstdio> 2 #include<cmath> 3 using namespace std; 4 struct ball 5 { 6 long long x,y,z;//开成long long防止运算溢出 7 }balls[1001];//存储球心信息 8 int up[1001],down[1001],tot1,tot2;//和上表面/下表面接触的球的球心编号及数组的大小标记 9 int fa[1001];//并查集组件 10 int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}//寻找父亲 11 double dis(ball i,ball j){return sqrt((i.x-j.x)*(i.x-j.x)+(i.y-j.y)*(i.y-j.y)+(i.z-j.z)*(i.z-j.z));}//求球心矩 12 int main() 13 { 14 int t; 15 scanf("%d",&t); 16 while(t--) 17 { 18 for(int i=1;i<=1000;i++) 19 fa[i]=i;//初始化fa数组 20 tot1=tot2=0; 21 int n,h,r; 22 scanf("%d%d%d",&n,&h,&r); 23 for(int i=1;i<=n;i++) 24 { 25 int x,y,z; 26 scanf("%d%d%d",&x,&y,&z); 27 balls[i].x=x;balls[i].y=y;balls[i].z=z; 28 if(z+r>=h)//球与上表面相交 29 up[++tot1]=i; 30 if(z-r<=0)//球与下表面相交 31 down[++tot2]=i; 32 } 33 for(int i=1;i<=n;i++)//判断任意两个球是否相交 34 for(int j=i+1;j<=n;j++) 35 if(dis(balls[i],balls[j])<=2*r) 36 fa[getfa(i)]=getfa(j);//若相交,合并 37 bool ans=false; 38 for(int i=1;i<=tot1;i++) 39 for(int j=1;j<=tot2;j++) 40 if(getfa(up[i])==getfa(down[j]))//如果从上面与下面相通,则为真 41 { 42 ans=true; 43 break; 44 } 45 if(ans) 46 printf("Yes "); 47 else 48 printf("No "); 49 } 50 return 0; 51 }
我只想提醒一点……判断球是否与上下表面相邻(读入处理的地方)一定一定不要加else!因为一个球可能同时与上下表面相连!我随手加个else30分就没有了………………