http://acm.hdu.edu.cn/showproblem.php?pid=3622
题意:
给定n个回合,每个回合给你两个点,每个回合只能选择一个点放置炸弹,在n个回合里选出n个点放置炸弹,炸弹的爆炸范围是一个圆形范围,半径可以控制。求满足每个炸弹爆炸的圆形区域不相交的条件下,的所有半径里面的最小半径最大值。
思路:
二分枚举两点之间的距离,如果存在两点距离小于等于枚举的距离时,则表示这两个点之间存在矛盾(i->j),然后根据2-sat构图方法建图,i->j' , j' -> i , j - >i' , i '->j然会通过2-sat判断是否满足条件,如果存在矛盾说明枚举的距离太小,如果不存在说明没机的距离太大....
//#pragma comment(linker,"/STACK:327680000,327680000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>
#define CL(arr, val) memset(arr, val, sizeof(arr))
#define ll long long
#define inf 0x7f7f7f7f
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#define L(x) (x) << 1
#define R(x) (x) << 1 | 1
#define MID(l, r) (l + r) >> 1
#define Min(x, y) (x) < (y) ? (x) : (y)
#define Max(x, y) (x) < (y) ? (y) : (x)
#define E(x) (1 << (x))
#define iabs(x) (x) < 0 ? -(x) : (x)
#define OUT(x) printf("%I64d\n", x)
#define lowbit(x) (x)&(-x)
#define Read() freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);
#define N 207
using namespace std;
const double eps = 1e-6;
struct point
{
double x,y;
}pt[N];
double dis[N][N];
int mat[N][N];
int dfn[N],low[N];
int belong[N],stk[N];
bool isn[N];
int cnt,idx,top;
int n;
int dblcmp(double x)
{
if (x > eps) return 1;
else if (x < -eps) return -1;
else return 0;
}
double getR(int i,int j)
{
double x = pt[i].x - pt[j].x;
double y = pt[i].y - pt[j].y;
return x*x + y*y;
}
void build(double mid)
{
int i,j;
CL(mat,0);
for (i = 0; i < 2*n; ++i)
{
isn[i] = false;
low[i] = dfn[i] = -1;
belong[i] = 0;
for (j = 0; j < 2*n; ++j)
{
if (i == j) continue;
if (dis[i][j] <= mid*mid)//存在矛盾的点建图
{
if (j%2 == 0)
{
mat[i][j + 1] = 1;
// mat[j + 1][i] = 1;
}
else
{
mat[i][j - 1] = 1;
// mat[j - 1][i] = 1;
}
if (i%2 == 0)
{
mat[j][i + 1] = 1;
// mat[i + 1][j] = 1;
}
else
{
mat[j][i - 1] = 1;
//mat[i - 1][j] = 1;
}
}
}
}
idx = top = cnt = 0;
}
void tarjan(int i)
{
int j;
dfn[i] = low[i] = ++idx;
stk[++top] = i; isn[i] = true;
for (j = 0; j < 2*n; ++j)
{
if (mat[i][j])
{
if (dfn[j] == -1)
{
tarjan(j);
low[i] = min(low[i],low[j]);
}
else if (isn[j])
{
low[i] = min(low[i],dfn[j]);
}
}
}
if (dfn[i] == low[i])
{
++cnt;
do
{
j = stk[top--];
isn[j] = false;
belong[j] = cnt;
}while (j != i);
}
}
bool solve(double mid)
{
int i;
build(mid);
//tarjan缩点
for (i = 0; i < 2*n; ++i)
{
if (dfn[i] == -1) tarjan(i);
}
//2-sat判断是否存在矛盾
for (i = 0; i < n; ++i)
{
if (belong[2*i] == belong[2*i + 1]) return false;
}
return true;
}
int main()
{
//Read();
int i,j;
while (~scanf("%d",&n))
{
for (i = 0; i < 2*n; ++i) scanf("%lf%lf",&pt[i].x,&pt[i].y);
// for (i = 0; i < 2*n; ++i) printf("%d %lf %lf\n",i,pt[i].x,pt[i].y);
double l = 0;
double r = 0;
for (i = 0; i < 2*n; ++i)
{
for (j = 0; j < 2*n; ++j)
{
if (i == j) dis[i][j] = 0;
else
{
dis[i][j] = getR(i,j);//计算距离的平方
r = max(r,dis[i][j]);
}
}
}
//printf(">>%lf\n",r);
r = sqrt(r);
double ans = 0,mid = 0;
while (dblcmp(l - r) < 0)//二分枚举
{
mid = (l + r)/2.0;
if (solve(mid))
{
l = mid;
ans = mid;
}
else
{
r = mid;
}
}
printf("%.2lf\n",ans/2.0);
}
return 0;
}