HDU 3622
解读题意
1.一对圆中必须选一个
2.求最小半径的最大值
分析对策
求最小值最大,用二分查找
连边后判定
转化构图
if(r*r*4>=dis(i*2+dx[k],j*2+dy[k])) {
//不能共存
//选了其中的一个个必须选另一对的另一个
add_edge(i*2+dx[k],j*2+(dy[k]^1));
add_edge(j*2+dy[k],i*2+(dx[k]^1));
}
注意
1.求距离不开根可以减小精度误差
2.二分精度要高每次移动0.0001左右
具体代码
#include<bits/stdc++.h>
using namespace std;
//每次两个圆中必须选一个
const double eps=1e-6;
const int M=205;
int n;
struct Round {
int a,b;
} A[M];
int asdf,head[M];
struct edge {
int to,nxt;
} G[M*M*2];
int dx[]= {0,0,1,1};
int dy[]= {0,1,0,1};
void add_edge(int a,int b) {
G[++asdf].to=b;
G[asdf].nxt=head[a];
head[a]=asdf;
}
bool mark[M];
int stk[M],top;
bool dfs(int x){
if(mark[x^1])return 0;
if(mark[x])return 1;
mark[x]=1;
stk[++top]=x;
for(int i=head[x];i;i=G[i].nxt){
if(!dfs(G[i].to))return 0;
}
return 1;
}
int sqr(int x){
return x*x;
}
int dis(int a,int b){
return sqr(A[a].a-A[b].a)+sqr(A[a].b-A[b].b);
}
bool check(double r) {
//两个圆不能重叠
asdf=0;
for(int i=0; i<2*n; i++) {
head[i]=mark[i]=0;
}
for(int i=0; i<n; i++) {
for(int j=i+1; j<n; j++) {
for(int k=0; k<4; k++) {
if(r*r*4>=dis(i*2+dx[k],j*2+dy[k])) {
//不能共存
//printf("%d %d\n",i*2+dx[k],j*2+dy[k]);
add_edge(i*2+dx[k],j*2+(dy[k]^1));
add_edge(j*2+dy[k],i*2+(dx[k]^1));
}
}
}
}
for(int i=0;i<2*n;i+=2){
if(!mark[i]&&!mark[i+1]){
top=0;
//printf("i=%d\n",i);
if(!dfs(i)){
while(top)mark[stk[top--]]=0;
if(!dfs(i+1))return 0;
}
}
}
return 1;
}
int main() {
while(scanf("%d",&n)==1) {
for(int i=0; i<2*n; i++) {
scanf("%d %d",&A[i].a,&A[i].b);
}
double L=0,R=15000,ans=0;
while(R-L>eps) {
double mid=(L+R)/2;
//printf("L=%lf R=%lf %lf\n",L,R,mid);
if(check(mid)) {
ans=mid;
L=mid+0.0001;
} else {
R=mid-0.0001;
}
}
printf("%.2f\n",ans);
}
return 0;
}