題目連結:

題目大意:

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


.