# hdu 3622 Bomb Game 2-SAT+二分答案 有N对点，求最大的半径R，使从每对点中选择一个点，且这N个点以自己为圆心，半径为R的圆两两不相交.(最大半径在所有半径相同情况下)

Problem Description
Robbie is playing an interesting computer game. The game field is an unbounded 2-dimensional region. There are N rounds in the game. At each round, the computer will give Robbie two places, and Robbie should choose one of them to put a bomb. The explosion area of the bomb is a circle whose center is just the chosen place. Robbie can control the power of the bomb, that is, he can control the radius of each circle. A strange requirement is that there should be no common area for any two circles. The final score is the minimum radius of all the N circles.
Robbie has cracked the game, and he has known all the candidate places of each round before the game starts. Now he wants to know the maximum score he can get with the optimal strategy.

Input
The first line of each test case is an integer N (2 <= N <= 100), indicating the number of rounds. Then N lines follow. The i-th line contains four integers x1i, y1i, x2i, y2i, indicating that the coordinates of the two candidate places of the i-th round are (x1i, y1i) and (x2i, y2i). All the coordinates are in the range [-10000, 10000].

Output
Output one float number for each test case, indicating the best possible score. The result should be rounded to two decimal places.

Sample Input
2 1 1 1 -1 -1 -1 -1 1 2 1 1 -1 -1 1 -1 -1 1

Sample Output
1.41 1.00

//

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=40000;
int V,E;//点数(1) 边数
struct edge//邻接表
{
int t,w;//u->t=w;
int next;
};
int p[500];//表头节点
edge G[maxn];
int l;
void init()
{
memset(p,-1,sizeof(p));
l=0;
}
//添加边
{
G[l].w=w;
G[l].t=t;
G[l].next=p[u];
p[u]=l++;
}
//tarjan算法 求有向图强联通分量
int dfn[maxn],lowc[maxn];
//dfn[u]节点u搜索的次序编号,lowc[u]u或者u的子树能够追溯到的栈中的最早的节点
int belg[maxn];//第i个节点属于belg[i]个强连通分量
int stck[maxn],stop;//stck栈
int instck[maxn];//第i个节点是否在栈中
int scnt;//强联通分量
int index;
void dfs(int i)
{
dfn[i]=lowc[i]=++index;
instck[i]=1;//节点i入栈
stck[++stop]=i;
for(int j=p[i];j!=-1;j=G[j].next)
{
int t=G[j].t;
//更新lowc数组
if(!dfn[t])//t没有遍历过
{
dfs(t);
if(lowc[i]>lowc[t]) lowc[i]=lowc[t];
}//t是i的祖先节点
else if(instck[t]&&lowc[i]>dfn[t]) lowc[i]=dfn[t];
}
//是强连通分量的根节点
if(dfn[i]==lowc[i])
{
scnt++;
int t;
do
{
t=stck[stop--];
instck[t]=0;
belg[t]=scnt;
}while(t!=i);
}
}
int tarjan()
{
stop=scnt=index=0;
memset(dfn,0,sizeof(dfn));
memset(instck,0,sizeof(instck));
for(int i=1;i<=V;i++)
{
if(!dfn[i]) dfs(i);
}
return scnt;
}
//
/*
n对东西，每对只能选一个（i0或i1），不能不选。即：A or _A = 1 , A xor _A = 1

i0-> j1 如果选i0的话必须选j1
j0-> i1如果选j0的话必须选i1.
1)选a必选b a->b
2)a必选 _a->a

*/
struct Node
{
int x,y;
};
int n;//n对点
Node a[300];
double dis(Node h,Node k)
{
return sqrt(0.0+(h.x-k.x)*(h.x-k.x)+(h.y-k.y)*(h.y-k.y));
}
int main()
{
while(scanf("%d",&n)==1)
{
//i和i+n只能选一个且必须选一个
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i+n].x,&a[i+n].y);
}
double l=0,r=10000000;
while(fabs(l-r)>1e-6)
{
double mid=(l+r)/2;
init();
V=2*n;
for(int i=1;i<=V;i++)
{
for(int j=i+1;j<=V;j++)//不用从1开始
{
if(dis(a[i],a[j])<=2*mid)//i,j不能共存
{
int ti,tj;
if(i<=n) ti=i+n;
else ti=i-n;
if(j<=n) tj=j+n;
else tj=j-n;
//选i只能选tj
//选j只能选ti
}
}
}
//如果i,i+n在同一个强联通分量中,则不能完成;否则可以实现
tarjan();
int flag=1;
for(int i=1;i<=n;i++)
{
if(belg[i]==belg[i+n])
{
flag=0;break;
}
}
//当半径足够小的时候是可以的
if(!flag) r=mid;
else l=mid;
}
printf("%.2lf\n",l);
}
return 0;
}

• 本文已收录于以下专栏：

举报原因： 您举报文章：hdu 3622 Bomb Game 2-SAT+二分答案 有N对点，求最大的半径R，使从每对点中选择一个点，且这N个点以自己为圆心，半径为R的圆两两不相交.(最大半径在所有半径相同情况下) 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)