hdu5299 Circles Game
2016-03-13 21:15
387 查看
Circles Game
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1427 Accepted Submission(s): 451
Problem Description
There are n circles on a infinitely large table.With every two circle, either one contains another or isolates from the other.They are never crossed nor tangent.
Alice and Bob are playing a game concerning these circles.They take turn to play,Alice goes first:
1、Pick out a certain circle A,then delete A and every circle that is inside of A.
2、Failling to find a deletable circle within one round will lost the game.
Now,Alice and Bob are both smart guys,who will win the game,output the winner's name.
Input
The first line include a positive integer T<=20,indicating the total group number of the statistic.
As for the following T groups of statistic,the first line of every group must include a positive integer n to define the number of the circles.
And the following lines,each line consists of 3 integers x,y and r,stating the coordinate of the circle center and radius of the circle respectively.
n≤20000,|x|≤20000,|y|≤20000,r≤20000。
Output
If Alice won,output “Alice”,else output “Bob”
Sample Input
2 1 0 0 1 6 -100 0 90 -50 0 1 -20 0 1 100 0 90 47 0 1 23 0 1
Sample Output
Alice Bob
Author
FZUACM
Source
2015 Multi-University Training Contest 1
显然圆的包含关系可以构成一片森林,然后问题就可以转化为:每一步可以删除森林的一棵树或者某树的一棵子树,不能删者输。这样,问题就变成经典的树上删边游戏了。
树上删边游戏有一个很重要的结论:叶子节点的SG值为0,中间节点的SG值为它的所有子节点的SG值加1后的异或和。(证明详见贾志豪论文《组合游戏略述——浅谈SG游戏的若干拓展及变形》)
现在,我们的主要问题就是如何把圆的包含关系转化为森林。这里要用到圆的扫描线算法。首先对于每个圆,创建两个时间点,一个进入一个离开,再对所有时间点从小到大排序。然后逐个处理时间点,用set维护所有圆,每遇到一个进入时间,分情况讨论圆的位置关系,然后把这个圆插入set中。每遇到一个离开时间,从set中删除这个圆。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #include<set> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 20010 using namespace std; int t,n,cnt,tt,tmp; int head[maxn],fa[maxn]; struct cir{int x,y,r;}a[maxn]; struct edge_type{int next,to;}e[maxn*2]; struct bor { int x,f,id; friend bool operator < (bor a,bor b) { if (a.x==b.x) return a.f<b.f; return a.x<b.x; } }q[maxn*2]; double get_h(int id,int x,int opt) { return a[id].y+opt*sqrt(a[id].r*a[id].r-(a[id].x-x)*(a[id].x-x)); } struct pos { int id,opt; pos(int a=0,int b=0){id=a;opt=b;} friend bool operator < (pos a,pos b) { if (a.id==b.id) return a.opt<b.opt; return get_h(a.id,tmp,a.opt)<get_h(b.id,tmp,b.opt); } }; set<pos> s; set<pos>::iterator it; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void add_edge(int x,int y) { e[++cnt]=(edge_type){head[x],y}; head[x]=cnt; fa[y]=x; } inline ll get(int x) { ll ret=0; for(int i=head[x];i;i=e[i].next) ret^=get(e[i].to); return ret+1; } int main() { t=read(); while (t--) { cnt=tt=0; memset(fa,0,sizeof(fa)); memset(head,0,sizeof(head)); n=read(); F(i,1,n) { a[i].x=read();a[i].y=read();a[i].r=read(); q[++tt]=(bor){a[i].x-a[i].r,1,i}; q[++tt]=(bor){a[i].x+a[i].r,-1,i}; } sort(q+1,q+tt+1); F(i,1,tt) { if (q[i].f==1) { tmp=q[i].x; it=s.lower_bound(pos(q[i].id,1)); if (it!=s.end()) { if (it->opt==1) add_edge(it->id,q[i].id); else if (fa[it->id]) add_edge(fa[it->id],q[i].id); } s.insert(pos(q[i].id,1)); s.insert(pos(q[i].id,-1)); } else { s.erase(pos(q[i].id,1)); s.erase(pos(q[i].id,-1)); } } ll sum=0; F(i,1,n) if (!fa[i]) sum=sum^get(i); puts(sum?"Alice":"Bob"); } }
相关文章推荐
- Java并发编程:Callable、Future和FutureTask
- HDOJ 1541 star(树状数组)
- iOS开发-进阶:iOS7中的多任务 - Background Fetch,Silent Remote Notifications,Background Transfer Service
- 数据结构之邻接表
- 数据库的悲观锁和乐观锁
- C++ / CLI 调用 C++ /Native 随记
- jmeter中基于oracle的JDBC Request的使用
- java多线程的线程池
- 面试题目二
- 软件包管理—rpm
- 操作系统三个简单的部分(Operating Systems in Three Easy Pieces)4.1
- 随便写写C++,看看Essential C++
- 使用Euclidean法求乘法逆
- POJ 1470 Closest Common Ancestors(离线tarjan-LCA)
- java ssh
- HDU 1846 (巴什博弈)
- 记程序第一次增补体会
- 中兴事件之痛 ——谁扒掉了中国电子整机产业的皇帝新衣(转)
- Java编程思想学习(十五) 注解
- 精辟