kongming_acm的专栏

如果不能正常显示代码 ,请右键->查看源文件 来查看源代码 里面有代码部分 另外由于网站原因 \n在博客里都显示是/n 请自己更改...

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

阅读更多
个人分类: acm_图论
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭