ZOJ 3717 Balloon 解题报告

 

BUPT Summer training 1


题意:现有n组气球(气球可以看成球体),每组有一个红气球一个蓝气球,已知每组气球的球心。要求从这n组气球中每组挑出一个气球放入花园中,不允许任意两球之间有重叠,求满足条件的气球的最大半径。

解法:因为每组就两个球,很容易想到二分+2 sat。

           首先二分枚举半径R。然后建图,若球x与球y的球心距小于R,则x->y',y->x'连边。跑一遍2 sat,并判断一组中的两个点是否在同一连通分量中。

           题目有坑,因为“The results should be rounded to three decimal places. You should promise that there is still no overlap for any two balloons after rounded.”所以四舍五入后以后还要判断一下是否会发生重叠。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 505
#define maxm 1000005
#define EPS 1e-4
int n;
struct node
{
    int v;
    int next;
}e[maxm];
int ecnt, pre[maxn];
int dfn[maxn], low[maxn], bel[maxn], stack[maxn];
bool instack[maxn];
int top, cnt, Dindex;
struct Node
{
    int x,y,z;
}p[maxn];
double dis[maxn][maxn];

void addEdge(int u,int v)
{
    e[ecnt].v=v;
    e[ecnt].next=pre[u];
    pre[u]=ecnt++;
}

double cal(int a,int b)
{
    return sqrt(1.0*(p[a].x-p[b].x)*(p[a].x-p[b].x)+(p[a].y-p[b].y)*(p[a].y-p[b].y)+(p[a].z-p[b].z)*(p[a].z-p[b].z));
}

void build(double key)
{
    ecnt=0;
    memset(pre,-1,sizeof(pre));
    for (int i=1;i<=2*n;i++)
        for (int j=1;j<=2*n;j++)
            if (i!=j&&i+n!=j&&i!=j+n&&dis[i][j]+EPS<key)
            {
                if (j<=n) addEdge(i,j+n);
                else addEdge(i,j-n);
                if (i<=n) addEdge(j,i+n);
                else addEdge(j,i-n);
            }
}

void tarjan(int u)
{
    dfn[u]=low[u]=++Dindex;
    stack[++top]=u;
    instack[u]=1;
    for (int i=pre[u];i!=-1;i=e[i].next)
    {
        int v=e[i].v;
        if (!dfn[v])
        {
            tarjan(v);
            if (low[v]<low[u])
                low[u]=low[v];
        }
        else if (instack[v]&&dfn[v]<low[u])
            low[u]=dfn[v];
    }
    int v;
    if (dfn[u]==low[u])
    {
        ++cnt;
        do
        {
            v=stack[top--];
            instack[v]=false;
            bel[v]=cnt;
        }while (v!=u);
    }
}

bool judge()
{
    Dindex=top=cnt=0;
    memset(dfn,0,sizeof(dfn));
    for (int i=1;i<=2*n;i++)
        if (!dfn[i])
            tarjan(i);
    for (int i=1;i<=n;i++)
        if (bel[i]==bel[i+n])
            return false;
    return true;
}

int main()
{
    //freopen("J:\\MyDocument\\Code\\input.txt","r",stdin);
    while (scanf("%d",&n)!=-1)
    {
        for (int i=1;i<=n;i++)
            scanf("%d%d%d%d%d%d",&p[i].x,&p[i].y,&p[i].z,&p[i+n].x,&p[i+n].y,&p[i+n].z);
        for (int i=1;i<=2*n;i++)
            for (int j=1;j<=2*n;j++)
                dis[i][j]=cal(i,j);
        double l=0, r=10000.0*sqrt(3.0),ans;
        while (r-l>0.000001)
        {
            double mid=(r+l)/2;
            build(mid);
            if (judge()) l=mid;
            else r=mid;
        }
        ans=(r+l)/2/2;
        char tmpstr[200];
        sprintf(tmpstr,"%.3f",ans);
        sscanf(tmpstr,"%lf",&ans);
        build(ans*2);
        if(!judge())    ans-=0.001;
        printf("%.3f\n",ans);
    }
    return 0;
}





你可能感兴趣的:(ZOJ 3717 Balloon 解题报告)