hdu 3622 Bomb Game

9 篇文章 0 订阅
3 篇文章 0 订阅

Bomb Game


很裸的2-sat。二分枚举半径,然后对于每个点i枚举j,其中j不是i'.如果dist(i,j)小于半径,那么就连边i->j', j->i',然后判断是否出现冲突。由于用double的话会出现精度误差,而给定点的坐标都是整数.所以,我们可以将其转化为整型处理,不进行开方操作,而比较的时候也是枚举两点间的距离。最后输出答案的时候在开方就行了。


/*
    author    : csuchenan
    prog      : hdu 3622
    algorithm : 2-sat
*/
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
using std::vector;
const int maxn= 100;
double eps = 1e-5;

vector<int> G[maxn*2+10];
struct Point{
    int x , y;
}point[maxn*2+10];
int d[maxn<<1][maxn<<1];

int dfn[maxn*2+10];
int low[maxn*2+10];
int col[maxn*2+10];
int stack[maxn*2+10];
bool ins[maxn*2+10];
int depth, top, color;
int n;

int dist(Point &a, Point &b){
    return (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y);
}

int min(int x, int y){
    if(x < y)
        return x;
    return y;
}

void predour(){
    memset(d, 0, sizeof(d));
    for(int i = 0; i < 2*n; i ++){
        for(int j = 0; j < 2*n ; j ++){
            d[i][j] = dist(point[i], point[j]);
        }
    }
}

void init(){
    memset(dfn, 0, sizeof(dfn));
    memset(ins, 0, sizeof(ins));
    memset(col, 0, sizeof(col));
    top = color = depth = 0;
    for(int i = 0; i < n*2; i ++){
        G[i].clear();
    }
}

void add_edge(int i, int j){
    G[i].push_back(j);
}

void tarjan(int v){
    dfn[v] = low[v] = ++ depth;
    ins[v] = true;
    stack[top ++] = v ;
    for(int i = 0; i != G[v].size(); i ++){
        int u = G[v][i];
        if(dfn[u]==0){
            tarjan(u);
            low[v] = min(low[v], low[u]);
        }
        else if(ins[u]){
            low[v] = min(low[v], dfn[u]);
        }
    }
    if(low[v]==dfn[v]){
        int k;
        color++;
        do{
            k = stack[--top];
            ins[k] = false;
            col[k] = color;
        }while(k!=v);
    }
}

bool two_sat(){
    //tarjan
    for(int i = 0; i < 2*n; i ++){
        if(dfn[i]==0){
            tarjan(i);
        }
    }
    //check
    for(int i = 0; i < n; i ++){
        if(col[i<<1] == col[i<<1|1]){
            return false;
        }
    }
    return true;
}

bool test(int R){
    init();//建图前先初始化
    //建图
    for(int i = 0; i < n; i ++){
        for(int j = i+1; j < n; j ++){
            if(d[i<<1][j<<1] < R){
                add_edge(i<<1, j<<1|1);
                add_edge(j<<1, i<<1|1);
            }
            if(d[i<<1|1][j<<1] < R){
                add_edge(i<<1|1, j<<1|1);
                add_edge(j<<1, i<<1);
            }
            if(d[i<<1|1][j<<1|1] < R){
                add_edge(i<<1|1, j<<1);
                add_edge(j<<1|1, i<<1);
            }
            if(d[i<<1][j<<1|1] < R){
                add_edge(i<<1, j<<1);
                add_edge(j<<1|1, i<<1|1);
            }
        }
    }
    //进行判断
    return two_sat();
}

int main(){
//    freopen("test.in", "r", stdin);
    while(scanf("%d", &n)!=EOF){
        for(int i = 0; i < n; i ++){
            scanf("%d%d%d%d", &point[i<<1].x, &point[i<<1].y, &point[i<<1|1].x, &point[i<<1|1].y);
        }
        predour();
        int l = 0 , r = 800000001;
        while(l < r){
            int m = (l + r)>>1;
            if(test(m))
                l = m+1;
            else
                r = m;
        }
        printf("%.2f\n", sqrt(l-1.0)*0.5);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值