【比赛】NOIP2017 奶酪
开始看到题以为是计算几何,后面发现不是,然后秒掉了。
可能写SPFA写多了,别人都是并查集做的,我用的是SPFA。
不过无所谓,我们把题目中的下底面和上表面看成两个点,那么就是求这两个点的连通性,如果连通,出Yes,否则出No。
转换成图论,如果两个洞的半径乘2大于等于两洞球心之间的距离,那么这两个洞就直接相通,连边,总共平方复杂度建图。
然后跑SPFA,如果终点的dis不为inf,就可到达。
#include<bits/stdc++.h> using namespace std; #define ll long long const int MAXN=1000+10,inf=0x3f3f3f3f; int T,n,h,p[MAXN],d[MAXN],to[MAXN*MAXN*2],nex[MAXN*MAXN*2],beg[MAXN],w[MAXN*MAXN*2],e,s,t; ll r; struct node{ int x,y,z; }; node hole[MAXN]; inline void read(int &x) { int data=0,w=1; char ch=0; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch>='0'&&ch<='9')data=(data<<3)+(data<<1)+(ch^'0'),ch=getchar(); x=data*w; } inline bool connect(int i,int j) { if(4ll*r*r-(ll)(hole[i].x-hole[j].x)*(ll)(hole[i].x-hole[j].x)>=(ll)(hole[i].y-hole[j].y)*(ll)(hole[i].y-hole[j].y)+(ll)(hole[i].z-hole[j].z)*(ll)(hole[i].z-hole[j].z))return true; else return false; } inline void insert(int x,int y,int z) { to[++e]=y; nex[e]=beg[x]; beg[x]=e; w[e]=z; } inline void Build() { for(register int i=1;i<=n;++i) for(register int j=i+1;j<=n;++j) if(connect(i,j))insert(i,j,1),insert(j,i,1); for(register int i=1;i<=n;++i) if(hole[i].z-r<=0)insert(s,i,1); for(register int i=1;i<=n;++i) if(hole[i].z+r>=h)insert(i,t,1); } inline void SPFA() { for(register int i=1;i<=t;++i)d[i]=inf; queue<int> q; q.push(s); p[s]=1; d[s]=0; while(!q.empty()) { int x=q.front(); q.pop(); p[x]=0; for(register int i=beg[x];i;i=nex[i]) if(d[to[i]]>d[x]+w[i]) { d[to[i]]=d[x]+w[i]; if(!p[to[i]]) { p[to[i]]=1; q.push(to[i]); } } } } inline void init() { e=0; memset(beg,0,sizeof(beg)); memset(p,0,sizeof(p)); } int main() { freopen("cheese.in","r",stdin); freopen("cheese.out","w",stdout); read(T); while(T--) { init(); read(n);read(h);scanf("%lld",&r); s=n+1,t=n+2; for(register int i=1;i<=n;++i)read(hole[i].x),read(hole[i].y),read(hole[i].z); Build(); SPFA(); if(d[t]<inf)printf("Yes\n"); else printf("No\n"); } return 0; }