[HDU3622][2-sat]Bomb Game

[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.
[Algorithm]
2-sat
[Analysis]
枚举r,对每一个r建图,如果在当前r下两个圆有交集就算做2-sat中的不能同时出现的两个元素,跑一下2-sat看看能不能成立。
[Pay Attention]
这种感觉是经典模型但却在细节上无法确定两个元素具体关系的问题,就要靠二分来解决
[Code]
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
using namespace std;

#define MAXN 210
#define MAXM 40010
#define EPS  1e-4

struct point 
{
    double x, y;
};

struct graph
{   
    int point[MAXN], next[MAXM], v[MAXM];
    int tot;
    graph()
    {
        memset(point, 0, sizeof(point));
        memset(next, 0, sizeof(next));
        memset(v, 0, sizeof(v));
        tot = 0;
    }
    void clear()
    {
        memset(point, 0, sizeof(point));
        memset(next, 0, sizeof(next));
        memset(v, 0, sizeof(v));
        tot = 0;

    }
    void insert(int x, int y)
    {
        tot++;
        next[tot] = point[x]; point[x] = tot; v[tot] = y;
    }
};  

inline double dis(point a, point b)
{
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

inline int group(int x)
{
    return (x + 1) / 2;
}

inline int part(int x)
{
    return ((x - 1) ^ 1) + 1;
}

graph ori;
point a[MAXN];
int dfsTime[MAXN], lessTime[MAXN], cct[MAXN], st[MAXN], top, cntCct;
int nowTime;
int n;

void tarjan(int now)
{
    nowTime++;
    dfsTime[now] = lessTime[now] = nowTime;
    st[++top] = now;
    for (int temp = ori.point[now]; temp; temp = ori.next[temp])
    {
        int tar = ori.v[temp];
        if (!dfsTime[tar])
        {
            tarjan(tar);
            lessTime[now] = min(lessTime[now], lessTime[tar]);
        }
        else
            if (!cct[tar])
                lessTime[now] = min(lessTime[now], dfsTime[tar]);
    }
    if (dfsTime[now] == lessTime[now])
    {
        cntCct++;
        while (1)
        {
            cct[st[top]] = cntCct; top--;
            if (st[top + 1] == now) break;
        }
    }
}

bool major(double r)
{
    memset(dfsTime, 0, sizeof(dfsTime));
    memset(lessTime, 0, sizeof(lessTime));
    memset(cct, 0, sizeof(cct));
    memset(st, 0, sizeof(st));
    top = 0; cntCct = 0; nowTime = 0;
    ori.clear();
    for (int i = 1; i <= n; i++)
    for (int j = i + 1; j <= n; j++)
        if (i != j && group(i) != group(j) && dis(a[i], a[j]) < r * 2)
        {
            ori.insert(i, part(j)); ori.insert(j, part(i));
        }
    for (int i = 1; i <= n; i++)
        if (!dfsTime[i])
            tarjan(i);
    for (int i = 1; i <= n / 2; i++)
        if (cct[i * 2 - 1] == cct[i * 2])
            return false;
    return true;
}

int main()
{
    //freopen("input.txt", "r", stdin);
    while (scanf("%d", &n) != EOF)
    {
        n *= 2;
        for (int i = 1; i <= n; i++)
            scanf("%lf%lf", &a[i].x, &a[i].y);
        double left = 0, right = 40000;
        while (right - left >= EPS)
        {
            double mid = (left + right) / 2;
            if (major(mid))
                left = mid;
            else
                right = mid;
        }
        printf("%.2f\n", left);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值