HDU 3622 Bomb Game 二分+2-sat

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;

}

  

 

你可能感兴趣的:(game)