题意:给你n个炸弹,每个炸弹都有两个位置放置,问你最大的爆炸半径,使得任意两个炸弹的爆炸范围不相交,可以相切,问半径是多少
思路:对半径进行二分,很显然是单调的,所以满足条件,然后由于点数不是很多,每次n2暴力建图跑sat
代码:(忘记跑tarjan对着空气debug半小时)
#include <bits/stdc++.h> using namespace std; const int maxn=1005; const int maxm=2000005; const double eps=1e-4; struct point { double x,y; }p[1005]; struct node { int to,nxt; } edge[maxm]; int head[maxn]; int low[maxn],dfn[maxn],stk[maxn],be[maxn]; int top,tim,num,tot;/// init -1 0 0 0 bool instk[maxn]; void add_edge(int u,int v) { edge[tot].to=v; edge[tot].nxt=head[u]; head[u]=tot++; } void init() { tot=0;num=0;tim=0; top=-1; memset(dfn,0,sizeof(dfn)); memset(head,-1,sizeof(head)); memset(instk,false,sizeof(instk)); } void tarjan(int u) { int v; low[u]=dfn[u]=++tim; stk[++top]=u; instk[u]=1; for(int k=head[u];~k;k=edge[k].nxt){ v=edge[k].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(instk[v]){ low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ ++num; do{ v=stk[top--]; instk[v]=false; be[v]=num; } while(u!=v); } } double dist(point a,point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } int n; void build(double x) { // printf("asd %d ",n*2); for(int i=0;i<2*n;i++){ for(int j=0;j<2*n;j++){ if((i/2!=j/2)&&(dist(p[i],p[j])<x)){ add_edge(i,j^1); add_edge(j,i^1); // printf("fuck %d %d %d %d ",i,j^1,j,i^1); } } } } bool check(double x) { init(); build(x*2.0); for(int i=0;i<2*n;i++){ if(!dfn[i])tarjan(i); } bool ok=true; for(int i=0;i<2*n;i+=2){ if(be[i]==be[i^1]){ ok=false;break; } } return ok; } int main() { while(~scanf("%d",&n)){ for(int i=0;i<n;i++){ scanf("%lf%lf%lf%lf",&p[i*2].x,&p[i*2].y,&p[i*2+1].x,&p[i*2+1].y); } // printf("test %d ",check(1.0)); double L=0.0,R=9999999.0; while(L+eps<R){ double mid=(L+R)*0.5; if(check(mid)){ L=mid; } else R=mid; } printf("%.2f ",L); } return 0; }