zoj 2318 Get Out! 计算几何spfa判负环
题意:给出n个圆心及半径,再给出一个特殊圆心及半径,问这个圆能不能逃出这n个圆的包围
首先先处理一下,将所有圆平移,使特殊圆在原点上,然后其他圆半径加上特殊圆的半径,这样特殊圆就可看成一个点而已,问题变为该点是否可以逃出实际上对于相交的两个圆,我们可以用他们圆心连线来代替它们。这样问题变为是否存在一个多边形,使得原点在这个多边行内部。
#include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> #include <queue> using namespace std; #define LL long long #define eps 1e-6 double pi=2*asin(1); struct circle { double x,y,r; }p[310]; struct Node { int v,nxt; double w; }node[310*310]; int n,vis[310],f[310],g[310],alloc; double d[310]; void add(int a,int b,double c) { node[alloc].v=b; node[alloc].nxt=g[a]; node[alloc].w=c; g[a]=alloc++; } double dist(int a,int b) { return hypot(fabs(p[a].x-p[b].x),fabs(p[a].y-p[b].y)); } bool spfa() { queue<int>Q; for(int i=1;i<=n;i++) { Q.push(i); vis[i]=1; f[i]=0; d[i]=0; } while(!Q.empty()) { int u=Q.front();Q.pop(); vis[u]=0; for(int son=g[u];son!=-1;son=node[son].nxt) { int v=node[son].v; double w=node[son].w; if(d[v]>eps+d[u]+w) { d[v]=d[u]+w; if(!vis[v]) { f[v]++; if(f[v]>=n) return false; vis[v]=1; Q.push(v); } } } } return true; } int main() { int T,i,j; scanf("%d",&T); while(T--) { scanf("%d",&n); for(i=1;i<=n;i++) scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].r); scanf("%lf%lf%lf",&p[0].x,&p[0].y,&p[0].r); for(i=1;i<=n;i++) { p[i].x-=p[0].x; p[i].y-=p[0].y; p[i].r+=p[0].r; } p[0].x=p[0].y=0; memset(g,-1,sizeof(g)); alloc=0; for(i=1;i<=n;i++) { for(j=i+1;j<=n;j++) { if(p[i].r+p[j].r-eps<dist(i,j)) continue; double C=acos((p[i].x*p[j].x+p[i].y*p[j].y)/dist(0,i)/dist(0,j)); bool flag=(p[i].x*p[j].y-p[j].x*p[i].y)>=0; add(i,j,flag?C:-C); add(j,i,!flag?C:-C); } } if(spfa()) printf("YES\n"); else printf("NO\n"); if(T) printf("\n"); } return 0; }