题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5299
题意:
平面上有n个两两不交的圆,现在有两个人轮流选取圆,每选到一个圆就要把这个圆及其内部的所有圆都删去,最后不能操作的人输,问谁有必胜策略。
分析:
由于圆两两不交,如果根据圆的包含关系建个图,可以得到一个森林,问题转化为树上的SG博弈,复杂度O(nlogn),
建图的时候需要用到圆的扫描线,具体可以搜索HDU3511 Prison Break的题解,
有关树上SG博弈的结论可以参看2009年国家集训队贾志豪的论文《组合游戏略述——浅谈SG游戏的若干拓展及变形》。
代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> using namespace std; typedef double db; const db eps=1e-6; const int MAXN=20005; int sgn(db x) { if(x>eps)return 1; if(x<-eps)return -1; return 0; } db Time; struct Circle { db x,y,r; db getX(int flag) { return x-flag*r; } db getY(int flag) { return y+flag*sqrt(max(r*r-(Time-x)*(Time-x),0.0)); } }c[MAXN]; struct Event { db x,y; int v,id; bool operator < (const Event &t)const { return sgn(x-t.x)==0 ? v<t.v : x<t.x; } }s[MAXN<<1]; vector<int>e[MAXN]; int p[MAXN],dep[MAXN]; struct node { int id,flag; node(){} node(int _id,int _flag):id(_id),flag(_flag){} bool operator < (const node &t)const { db y1=c[id].getY(flag); db y2=c[t.id].getY(t.flag); return sgn(y1-y2)==0 ? flag<t.flag : y1<y2; } }; void build(int n) { memset(dep,0,sizeof(dep)); for(int i=0;i<=n;i++)e[i].clear(); for(int i=1;i<=n;i++) { s[2*i-1].x=c[i].x-c[i].r; s[2*i-1].v=1; s[2*i].x=c[i].x+c[i].r; s[2*i].v=-1; s[2*i-1].y=s[2*i].y=c[i].y; s[2*i-1].id=s[2*i].id=i; } sort(s+1,s+2*n+1); set<node>Line; set<node>::iterator up,down; for(int i=1;i<=2*n;i++) { Time=s[i].x; if(s[i].v<0) { Line.erase(node(s[i].id,1)); Line.erase(node(s[i].id,-1)); } else { down=Line.lower_bound(node(s[i].id,1)); up=down; if(down==Line.begin() || up==Line.end()) { e[0].push_back(s[i].id); p[s[i].id]=0; dep[s[i].id]=1; } else if((--down)->id == up->id) { e[down->id].push_back(s[i].id); p[s[i].id]=down->id; dep[s[i].id]=dep[down->id]+1; } else { if(dep[down->id] > dep[up->id]) { e[up->id].push_back(s[i].id); p[s[i].id]=up->id; dep[s[i].id]=dep[up->id]+1; } else if(dep[up->id] > dep[down->id]) { e[down->id].push_back(s[i].id); p[s[i].id]=down->id; dep[s[i].id]=dep[down->id]+1; } else { e[p[down->id]].push_back(s[i].id); p[s[i].id]=p[down->id]; dep[s[i].id]=dep[p[down->id]]+1; } } Line.insert(node(s[i].id,1)); Line.insert(node(s[i].id,-1)); } } } int dfs(int u) { int res=0; for(int i=0;i<e[u].size();i++) res^=dfs(e[u][i]); return res+(u!=0); } int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&c[i].x,&c[i].y,&c[i].r); build(n); if(dfs(0))printf("Alice\n"); else printf("Bob\n"); } return 0; }