题意:有一个游戏,有n个回合,每回合可以在指定的2个区域之一放炸弹,炸弹范围是一个圈,要求每回合的炸弹范围没有重合。得分是炸弹半径最小的值。求可以得到的最大分数。

思路:二分+2SAT。

二分炸弹范围,再根据有无重合建图,用2SAT判定。

#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
using namespace std;
;
struct TwoSAT
{
    int n;
    vector<];
    ];
    ],c;
    bool dfs(int x)
    {
        ]) return false;
        if(mark[x]) return true;
        mark[x]=true;
        S[c++]=x;
        ; i<G[x].size(); ++i)
            if(!dfs(G[x][i])) return false;
        return true;
    }
    void init(int n)
    {
        this->n=n;
        ; i<n*; ++i) G[i].clear();
        memset(mark,,sizeof(mark));
    }
    void add_clause(int x,int xval,int y,int yval)
    {
        x=x*+xval;
        y=y*+yval;
        G[x^].push_back(y);
        G[y^].push_back(x);
    }
    bool solve()
    {
        ; i<n*; i+=)
        {
            ])
            {
                c=;
                if(!dfs(i))
                {
                    ) mark[S[--c]]=false;
                    )) return false;
                }
            }
        }
        return true;
    }
};
struct Point
{
    int x,y;
};
Point p[][];
int n;
TwoSAT solver;
double distan(Point a,Point b)
{
    return sqrt((a.x*1.0-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool judge(double d)
{
    solver.init(n);
    ; i<n; ++i); a<; ++a)
            ; j<n; ++j); b<; ++b)
                    *d)
                        solver.add_clause(i,a^,j,b^);
    return solver.solve();
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {

        ; i<n; ++i)
        {
            ; j<; ++j)
                scanf("%d%d",&p[i][j].x,&p[i][j].y);
        }
        ;
        solver.init(n);
        ; i<n; ++i); a<; ++a)
                ; j<n; ++j); b<; ++b)
                        maxi=max(maxi,distan(p[i][a],p[j][b]));
        ,R=maxi;
        ; i<; ++i)
        {
            ;
            if(judge(mid)) L=mid;
            else R=mid;
        }
        printf("%.2lf\n",L);
    }
    ;
}
05-06 02:59