【HDU 3622】 Bomb Game(2-SAT)

題意:

一個遊戲有nn輪,每輪提供給你兩個座標,你選擇其中一個放置炸彈,到最後會放置nn個炸彈,要保證任意兩個炸彈的爆炸區域不會相交,每個炸彈的爆炸半徑由你來決定,你的目的是使最小的半徑最大。

題解:

考慮二分半徑,對於半徑rrO(n2)O(n^2)的建立約束關係,利用2SAT2-SAT判斷可行性。時間複雜度O(n2log(n))O(n^2log(n))

代碼:

#include<bits/stdc++.h>

using namespace std;
const int N = 500;
int n,m,scc,idx,color[N],low[N],dfn[N];
vector<int> G[N];
bool is_instack[N];stack<int> sta;
void init(int n){
    scc=idx=0;
    for(int i=1;i<=2*n;i++){
        low[i]=dfn[i]=is_instack[i]=color[i]=0;
        G[i].clear();
    }
    while(!sta.empty()) sta.pop();
}
void Tarjan(int u){
    low[u]=dfn[u]=++idx;
    sta.push(u);is_instack[u]=1;
    for(int v:G[u]){
        if(!dfn[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(is_instack[v]){
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u]){
        ++scc;
        while(1){
            int temp=sta.top();
            color[temp]=scc;
            is_instack[temp]=0;
            sta.pop();
            if(temp==u) break;
        }
    }
}
struct Point{
    double x,y;
}p[N][2];
double dis(Point a,Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool check(double r){
    init(n);
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            if(2.0*r>dis(p[i][0],p[j][0])){
                //cout<<dis(p[i][0],p[j][0])<<endl;
                G[i].push_back(j+n);
                G[j].push_back(i+n);
            }
            if(2.0*r>dis(p[i][1],p[j][1])){
                G[i+n].push_back(j);
                G[j+n].push_back(i);
            }
            if(2.0*r>dis(p[i][0],p[j][1])){
                G[i].push_back(j);
                G[j+n].push_back(i+n);
            }
            if(2.0*r>dis(p[i][1],p[j][0])){
                G[i+n].push_back(j+n);
                G[j].push_back(i);
            }
        }
    }
    for(int i=1;i<=2*n;i++){
        if(!dfn[i]) Tarjan(i);
    }
    for(int i=1;i<=n;i++){
        if(color[i]==color[i+n]){
            return 0;
        }
    }
    return 1;
}
int main(){
    while(scanf("%d",&n)!=EOF){
        init(n);
        for(int i=1;i<=n;i++){
            scanf("%lf %lf %lf %lf",&p[i][0].x,&p[i][0].y,&p[i][1].x,&p[i][1].y);   
        }
        // cout<<check(1.41)<<endl;
        double l=0;double r=1e18;
        for(int i=1;i<=100;i++){
            double mid=(l+r)*0.5;
            if(check(mid)) l=mid;
            else r=mid;
        }
        printf("%.2lf\n",l);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章