hdu 3622 Bomb Game 2-SAT+二分答案 有N對點,求最大的半徑R,使從每對點中選擇一個點,且這N個點以自己爲圓心,半徑爲R的圓兩兩不相交.(最大半徑在所有半徑相同情況下)

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.
 

Input
The first line of each test case is an integer N (2 <= N <= 100), indicating the number of rounds. Then N lines follow. The i-th line contains four integers x1i, y1i, x2i, y2i, indicating that the coordinates of the two candidate places of the i-th round are (x1i, y1i) and (x2i, y2i). All the coordinates are in the range [-10000, 10000].
 

Output
Output one float number for each test case, indicating the best possible score. The result should be rounded to two decimal places.
 

Sample Input
2 1 1 1 -1 -1 -1 -1 1 2 1 1 -1 -1 1 -1 -1 1
 

Sample Output
1.41 1.00

//


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=40000;
int V,E;//點數(1) 邊數
struct edge//鄰接表
{
    int t,w;//u->t=w;
    int next;
};
int p[500];//表頭節點
edge G[maxn];
int l;
void init()
{
    memset(p,-1,sizeof(p));
    l=0;
}
//添加邊
void addedge(int u,int t,int w)//u->t=w;
{
    G[l].w=w;
    G[l].t=t;
    G[l].next=p[u];
    p[u]=l++;
}
//tarjan算法 求有向圖強聯通分量
int dfn[maxn],lowc[maxn];
//dfn[u]節點u搜索的次序編號,lowc[u]u或者u的子樹能夠追溯到的棧中的最早的節點
int belg[maxn];//第i個節點屬於belg[i]個強連通分量
int stck[maxn],stop;//stck棧
int instck[maxn];//第i個節點是否在棧中
int scnt;//強聯通分量
int index;
void dfs(int i)
{
    dfn[i]=lowc[i]=++index;
    instck[i]=1;//節點i入棧
    stck[++stop]=i;
    for(int j=p[i];j!=-1;j=G[j].next)
    {
        int t=G[j].t;
        //更新lowc數組
        if(!dfn[t])//t沒有遍歷過
        {
        dfs(t);
        if(lowc[i]>lowc[t]) lowc[i]=lowc[t];
        }//t是i的祖先節點
        else if(instck[t]&&lowc[i]>dfn[t]) lowc[i]=dfn[t];
    }
    //是強連通分量的根節點
    if(dfn[i]==lowc[i])
    {
    scnt++;
    int t;
    do
    {
        t=stck[stop--];
        instck[t]=0;
        belg[t]=scnt;
        }while(t!=i);
    }
}
int tarjan()
{
    stop=scnt=index=0;
    memset(dfn,0,sizeof(dfn));
    memset(instck,0,sizeof(instck));
    for(int i=1;i<=V;i++)
    {
        if(!dfn[i]) dfs(i);
    }
    return scnt;
}
//
/*
n對東西,每對只能選一個(i0或i1),不能不選。即:A or _A = 1 , A xor _A = 1
還存在一些約束關係(i0,j0),表示i0不能跟j0一起選。那需連邊:
i0-> j1 如果選i0的話必須選j1
j0-> i1如果選j0的話必須選i1.
 1)選a必選b a->b
 2)a必選 _a->a
對這個新圖求SCC,同一SCC的要麼全選,要麼都不選。
如果發現a,_a在同一SCC,表明矛盾了。
*/
struct Node
{
    int x,y;
};
int n;//n對點
Node a[300];
double dis(Node h,Node k)
{
    return sqrt(0.0+(h.x-k.x)*(h.x-k.x)+(h.y-k.y)*(h.y-k.y));
}
int main()
{
    while(scanf("%d",&n)==1)
    {
        //i和i+n只能選一個且必須選一個
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i+n].x,&a[i+n].y);
        }
        double l=0,r=10000000;
        while(fabs(l-r)>1e-6)
        {
            double mid=(l+r)/2;
            init();
            V=2*n;
            for(int i=1;i<=V;i++)
            {
                for(int j=i+1;j<=V;j++)//不用從1開始
                {
                    if(dis(a[i],a[j])<=2*mid)//i,j不能共存
                    {
                        int ti,tj;
                        if(i<=n) ti=i+n;
                        else ti=i-n;
                        if(j<=n) tj=j+n;
                        else tj=j-n;
                        //選i只能選tj
                        addedge(i,tj,1);
                        //選j只能選ti
                        addedge(j,ti,1);
                    }
                }
            }
            //如果i,i+n在同一個強聯通分量中,則不能完成;否則可以實現
            tarjan();
            int flag=1;
            for(int i=1;i<=n;i++)
            {
                if(belg[i]==belg[i+n])
                {
                    flag=0;break;
                }
            }
            //當半徑足夠小的時候是可以的
            if(!flag) r=mid;
            else l=mid;
        }
        printf("%.2lf\n",l);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章