2 1 1 1 -1 -1 -1 -1 1 2 1 1 -1 -1 1 -1 -1 1
1.41 1.00
给n对炸弹可以放置的坐标位置,每对只能选一个,每个炸弹爆炸的范围半径都一样,
控制爆炸的半径使得所有的爆炸范围都不相交,求解这个最大半径.
直接二分答案,跑一波2-SAT就好。
//#include <bits/stdc++.h> #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int MAXN = 1e5+7; const double eps = 1e-5; int x[MAXN],y[MAXN]; struct node { int v,next; } edge[MAXN]; int head[MAXN],index; void add_edge(int u,int v) { edge[index].v=v; edge[index].next=head[u]; head[u]=index++; } int DFN[MAXN],low[MAXN],stack_[MAXN],in_stack[MAXN],belong[MAXN]; int cir,top,temp; void Tarjan(int u) { int p; DFN[u]=low[u]=++temp; in_stack[u]=1; stack_[top++]=u; for(int i=head[u]; i+1; i=edge[i].next) { int v=edge[i].v; if(!DFN[v]) { Tarjan(v); low[u]=min(low[u],low[v]); } else if(in_stack[v]) low[u]=min(low[u],DFN[v]); } if(low[u]==DFN[u]) { ++cir; do { p=stack_[--top]; in_stack[p]=0; belong[p]=cir; } while(p!=u); } } double dist(int i,int j) { return sqrt((double)(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); } int main() { int n,m; while(scanf("%d",&n)!=EOF) { for(int i=0; i<n<<1; ++i) scanf("%d%d",&x[i],&y[i]); double ans; double l=0.0,r=40000.0,mid; while(r-l>=eps) { mid=(l+r)/2.0; temp=cir=top=index=0; memset(DFN,0,sizeof(DFN)); memset(head,-1,sizeof(head)); memset(in_stack,0,sizeof(in_stack)); memset(belong,0,sizeof(belong)); for(int i=0; i<n<<1; ++i) for(int j=i+1; j<n<<1; ++j) { if(j-i==1&&i&1==0)continue; if(dist(i,j)<mid*2.0) { add_edge(j^1,i); add_edge(i^1,j); } } for(int i=0; i<n<<1; ++i) if(!DFN[i])Tarjan(i); int flag=0; for(int i=0; i<n; ++i) if(belong[i<<1]==belong[(i<<1)^1]) { flag=1; break; } if(!flag){ans=mid;l=mid;} else r=mid; } printf("%.2lf\n",ans); } return 0; }