hdu 3622 Bomb Game(二分答案+2-sat判断答案可行性)

题目链接:

点击打开链接

题目大意:

有n个炸弹,每个炸弹的放置位置有两个可选,每个炸弹的爆炸范围不能交叉,问我所有炸弹的中爆炸范围最小的那个炸弹的爆炸范围最大是多少

题目分析:

首先炸弹放置的位置是两个,那么就是2-sat问题,我们只需要二分答案,然后判断答案是否合法,如果答案合法,那么答案就可能是更大的值,每次二分出的mid值作为所有炸弹的爆炸范围,如果他们能够得到不会交叉的解,那么说明当前方案可行,建边的时候就是对于任意两个点,枚举他们各自的两个点是否会相交,如果会,那么选其中一个就一定不选另一个

代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <stack>
#include <cmath>
#define MAX 207
#define eps 1e-9

using namespace std;

int mark[MAX],dfn[MAX],low[MAX],belong[MAX],times,cnt;
vector<int> e[MAX];
stack<int> s;

struct Point
{
    double x,y;
}p[MAX];

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

void tarjan ( int u )
{
    dfn[u] = low[u] = ++times;
    mark[u] = 1;
    s.push ( u );
    int len = e[u].size();
    for ( int i= 0 ; i < len ; i++ )
    {
        int v = e[u][i];
        if ( !mark[v] )
        {
            tarjan ( v );
            low[u] = min ( low[u] , low[v] );
        }
        if ( mark[v] == 1 )
            low[u] = min ( low[u] , dfn[v] );
    }
    if ( dfn[u] == low[u] )
    {
        int temp;
        do
        {
            temp = s.top();
            belong[temp] = cnt;
            mark[temp] = 2;
            s.pop();
        }while ( temp != u );
        cnt++;
    }
}

void init ( )
{
    memset ( mark , 0 , sizeof ( mark ));
    for ( int i = 0 ; i < MAX ; i++ )
        e[i].clear();
    while ( !s.empty() ) s.pop();
    times = cnt = 0;
}

int n,m;

bool check ( double mid )
{
    init();
    for ( int i = 0 ; i < n ; i++ )
        for ( int j = i+1 ; j < n ; j++ )
        {
            int x = i<<1 , y = j<<1;
            int u = i<<1|1 , v = j<<1|1;
            /*if ( dis( p[x] , p[y] ) + eps < mid && dis ( p[u] , p[v] ) + eps < mid
                 dis( p[u] , p[y] ) + eps < mid && dis ( p[x] , p[v] ) + eps < mid )
                    return false;*/
            if ( dis ( p[x] , p[y] ) + eps < mid*2 )
            {
                e[x].push_back( v );
                e[y].push_back( u );
            }
            if ( dis ( p[u] , p[v] ) + eps < mid*2 )
            {
                e[u].push_back ( y );
                e[v].push_back ( x );
            }
            if ( dis ( p[x] , p[v]) + eps < mid*2 )
            {
                e[x].push_back ( y );
                e[v].push_back ( u );
            }
            if ( dis ( p[u] , p[y] ) + eps < mid*2 )
            {
                e[u].push_back ( v );
                e[y].push_back ( x );
            }
        }

    for ( int i = 0 ; i < 2*n ; i++ )
        if ( !mark[i] ) tarjan ( i );

    for ( int i = 0 ; i < n ; i++ )
        if ( belong[i<<1] == belong[i<<1|1] )
            return false;
    return true;
}

int main ( )
{
    while ( ~scanf ( "%d" , &n ))
    {
        for ( int i = 0 ; i < n ; i++ )
            scanf ( "%lf%lf%lf%lf" , &p[i<<1].x , &p[i<<1].y , &p[i<<1|1].x , &p[i<<1|1].y );
        //cout << "YES" << endl;
        double l = 0 , r = 10000.0, mid;
        int times = 100;
        while ( times-- )
        {
            mid = ( l + r )/2.0;
            if ( check ( mid ) ) l = mid;
            else r = mid;
        }
        printf ( "%.2lf\n" , l );
    }
}


你可能感兴趣的:(图论,Tarjan,二分)