ZOJ 3717: Balloon

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3717


题意:

有N组气球,每组有一个蓝气球以及一个红气球可供选择,它们各自有自己的圆心坐标。在每组中选择一个气球吹起来,要求把所有的气球吹到一样大,气球和气球之间不能重叠。问最多可以吹多大。


算法:

典型的二分求值+2-SAT判定。

o(n^2)预处理出距离。

每次判定,若两气球在当前半径值下会重叠,则本轮不能同时选择。


代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
const int MAXN=500;
int low[MAXN],dep[MAXN],blk[MAXN];
int x[MAXN],y[MAXN],z[MAXN];
int blkn;
vector<int>m[MAXN];
stack<int>stk;

double dis(int i, int j) {
    return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j]));
}

void tarjan(int p,int u) {
    if(dep[u]==-1) {
        int tmp=low[u]=dep[u]=(p==-1)?0:dep[p]+1;
        stk.push(u);
        for(int i=0; i<m[u].size(); i++) {
            int v=m[u][i];
            tarjan(u,v);
            tmp=min(tmp,low[v]);
        }
        low[u]=tmp;
        if(low[u]==dep[u]) {
            while(1) {
                int v=stk.top();
                stk.pop();
                blk[v]=blkn;
                low[v]=INT_MAX;
                if(u==v)break;
            }
            blkn++;
        }
    }
}

bool check(int n,double r) {
    memset(dep,-1,sizeof(dep));
    blkn=0;
    while(!stk.empty())
        stk.pop();
    for(int i=0; i<2*n; i++) {
        m[i].clear();
    }
    for(int i=0; i<n; i++) {
        for(int j=i+1; j<n; j++) {
            for(int a=(i<<1); a<=(i<<1|1); a++) {
                for(int b=(j<<1); b<=(j<<1|1); b++) {
                    if(dis(a,b)<2*r) {
                        m[a].push_back(b^1);
                        m[b].push_back(a^1);
                    }
                }
            }
        }
    }
    for(int i=0; i<2*n; i++) {
        tarjan(-1,i);
    }
    for(int i=0; i<2*n; i+=2) {
        if(blk[i]==blk[i|1]) {
            return false;
        }
    }
    return true;
}

int main() {
    int n;
    while(scanf("%d",&n)==1) {
        for(int i=0; i<n; i++) {
            scanf("%d%d%d",&x[i<<1],&y[i<<1],&z[i<<1]);
            scanf("%d%d%d",&x[i<<1|1],&y[i<<1|1],&z[i<<1|1]);
        }
        double l=0.0;
        double r=10000.0;
        while(r-l>1e-3) {              //此处有问题,详见评论
            double mid=(l+r)/2.0;
            if(check(n,mid)) {
                l=mid;
            } else {
                r=mid;
            }
        }
        printf("%.3lf\n",(l+r)/2.0);
    }
    return 0;
}


你可能感兴趣的:(ZOJ 3717: Balloon)