这题是一个二分半径+判定的题,但是开始不知道怎么去判定,以前听别人提起过sat问题,感觉这题是一个2sat模型,因为有一些限制比如:同一组两个里面只能选一个,两个球重叠时只能选其中的一个等,这很符合2sat的模型,于是去翻了下白书上2sat问题的解法实现,建图后直接用搜索判定,我用这种方法写了写,开始提交wa了几次,wa的原因是:题目说在round之后也要保证不重叠,那就只有舍掉小数点3位以后的数了,后面就ac了,代码如下:
#include<stdio.h> #include<math.h> #include<string.h> struct E { int t,next; }edge[200010]; int ant,head[500]; void add(int a,int b) { edge[ant].t=b; edge[ant].next=head[a]; head[a]=ant++; } int vis[500],sta[500],sp,n; int check(int root) { if(vis[root^1]) return 0; if(vis[root]) return 1; sta[sp++]=root; vis[root]=1; int i; for(i=head[root];i!=-1;i=edge[i].next) if(check(edge[i].t)==0) return 0; return 1; } int dfs(void) { int i; memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++) { if(vis[2*i]||vis[2*i+1]) continue; sp=0; if(!check(2*i)){ while(sp>0) vis[sta[--sp]]=0; if(!check(2*i+1)) return 0; } } return 1; } struct point { double x,y,z; point(double a=0,double b=0,double c=0):x(a),y(b),z(c){} }P[210][2]; double dis(point a,point b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z)); } double const eps=1e-11; void init(double d) { int i,j,k,g; ant=0;memset(head,-1,sizeof(head)); for(i=1;i<=n;i++) { for(j=i+1;j<=n;j++) { for(k=0;k<2;k++){ for(g=0;g<2;g++){ if(dis(P[i][k],P[j][g])<d){ add(i*2+k,j*2+(g^1)); add(j*2+g,i*2+(k^1)); } } } } } } int main() { int i; double ans,l,r; while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++){ scanf("%lf%lf%lf",&P[i][0].x,&P[i][0].y,&P[i][0].z); scanf("%lf%lf%lf",&P[i][1].x,&P[i][1].y,&P[i][1].z); } l=0;r=dis(point(0,0,0),point(10000,10000,10000)); while(r-l>1e-4){ ans=(r+l)/2; init(2*ans); if(dfs()) l=ans; else r=ans; } printf("%.3lf\n",ans-0.0005); } return 0; }