题意:有一个游戏,有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); } ; }