您的位置:首页 > 其它

HDU 3622 Bomb Game 二分+2-sat

2013-01-29 09:23 387 查看
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
;

double dis

;
int mat

;

int dfn
,low
;
int belong
,stk
;
bool isn
;

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;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: