题意:给n对炸弹,每对炸弹选其中一个爆炸。
每个炸弹爆炸的半径相同 圆不能相交, 求最大半径
二分半径, 枚举n*2个炸弹
若i炸弹与j炸弹的距离小于半径*2 则建边
比如 第一对炸弹的第一个 与 第二对炸弹的第一个 距离小于半径*2
则 建立 第一对炸弹的第一个$Rightarrow $第二对炸弹的第二个 、第二对炸弹的第一个$Rightarrow $第一对炸弹的第二个
然后 通过判断能否取到n个炸弹 来判断 能否取该半径
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 typedef pair<double, double> PI; 5 const double eps=1e-6; 6 #define INF 0x3f3f3f3f 7 8 const int N=105*2; 9 const int M=N*N; 10 //注意n是拆点后的大小 即 n <<= 1 N为点数(注意要翻倍) M为边数 i&1=0为i真 i&1=1为i假 11 struct Edge 12 { 13 int to, nex; 14 }edge[M]; 15 //注意 N M 要修改 16 int head[N], edgenum; 17 void addedge(int u, int v) 18 { 19 Edge E={v, head[u]}; 20 edge[edgenum]=E; 21 head[u]=edgenum++; 22 } 23 24 bool mark[N]; 25 int Stack[N], top; 26 void init() 27 { 28 memset(head, -1, sizeof(head)); 29 edgenum=0; 30 memset(mark, 0, sizeof(mark)); 31 } 32 33 bool dfs(int x) 34 { 35 if(mark[x^1]) 36 return false;//一定是拆点的点先判断 37 if(mark[x]) 38 return true; 39 mark[x]=true; 40 Stack[top++]=x; 41 for(int i=head[x];i!=-1;i=edge[i].nex) 42 if(!dfs(edge[i].to)) 43 return false; 44 return true; 45 } 46 47 bool solve(int n) 48 { 49 for(int i=0;i<n;i+=2) 50 if(!mark[i] && !mark[i^1]) 51 { 52 top=0; 53 if(!dfs(i)) 54 { 55 while(top) 56 mark[Stack[--top]]=false; 57 if(!dfs(i^1)) 58 return false; 59 } 60 } 61 return true; 62 } 63 64 PI a[205]; 65 double dis(PI a, PI b) 66 { 67 return sqrt((a.first-b.first)*(a.first-b.first)+(a.second-b.second)*(a.second-b.second)); 68 } 69 70 int main() 71 { 72 int n; 73 while(~scanf("%d", &n)) 74 { 75 for(int i=0;i<n;i++) 76 { 77 double x1, y1, x2, y2; 78 scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); 79 a[i*2]=make_pair(x1, y1); 80 a[i*2+1]=make_pair(x2, y2); 81 } 82 double l=0, r=15000; 83 while(r-l>=eps) 84 { 85 double m=(l+r)/2.0; 86 init(); 87 for(int i=0;i<n*2;i++) 88 for(int j=i+1+!(i&1);j<2*n;j++) 89 if(dis(a[i], a[j])<2*m) 90 { 91 addedge(i, j^1); 92 addedge(j, i^1); 93 } 94 if(solve(n*2)) 95 l=m; 96 else 97 r=m; 98 } 99 printf("%.2f ", r); 100 } 101 return 0; 102 }