Circles Game
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 251 Accepted Submission(s): 51
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.
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。
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
题意:有很多圆,相互包含或者相离,可以选着一个圆删掉,所有在该圆内的圆都会被删掉。Alice和Bob在玩游戏,Alice先手,问谁会赢。
方法:
先预处理出每个圆与包含该圆的最小圆,建立一片森林。
用对圆按半径排序,用线段树按x坐标排序,把x坐标相同的圆放到同一个结点中。处理一个圆的时候,用log的复杂度查到哪些圆满足x坐标满足X'- r,X'+r,然后枚举这些圆,看是否被该圆直接包含。然后建立一片森林。
建立虚拟结点,把森林连成一棵树。
此时游戏转化为每次删除树上一条边,并把所有无法到达根的点全部删除。最后不能删边的人输。
树上的删边游戏,看论文《《OI2009-组合游戏略述——浅谈SG游戏的若干拓展及变形》》
每个结点的sg函数 = ^(孩子结点的sg+1)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define maxn 200000
int lc[maxn],rc[maxn],size[maxn];
int cnt;
void init(){
lc[0] = rc[0] = size[0] = 0;
cnt = 1;
}
void build(int u,int l,int r){
lc[u] = rc[u] = size[u] = 0;
if(l == r) return ;
lc[u] = cnt++;
rc[u] = cnt++;
build(lc[u],l,(l+r)/2);
build(rc[u],(l+r)/2+1,r);
}
vector<int>head[maxn];
void add(int u,int l,int r,int p,int id){
if(l == r){
size[u]++;
head[l].push_back(id);
return ;
}
int mid = (l+r)/2;
if(p > mid)
add(rc[u],mid+1,r,p,id);
else
add(lc[u],l,mid,p,id);
size[u]++;
}
struct Point{
int x,y,r;
};
Point p[maxn];
int isin(Point a,Point b){
int x = a.x-b.x;
int y = a.y-b.y;
if(x*x+y*y<=b.r*b.r) return 1;
return 0;
}
vector<int> edge[maxn];
int in[maxn];
void query(int u,int l,int r,int id){
if(size[u] < 0) return;
if(l > p[id].x+p[id].r) return;
if(r < p[id].x-p[id].r) return;
if(l == r){
for(int i = 0;i < head[l].size();i++){
int u = head[l][i];
if(isin(p[u],p[id])){
edge[id].push_back(u);
in[u]++;
head[l][i] = head[l][head[l].size()-1];
head[l].pop_back();
i--;
}
}
return ;
}
int mid = (l+r)/2;
query(lc[u],l,mid,id);
query(rc[u],mid+1,r,id);
size[u] = size[rc[u]]+size[lc[u]];
}
int comp(Point a,Point b){
return a.r < b.r;
}
int dfs(int u){
int ans = 0;
for(int i = 0;i < edge[u].size();i++){
ans ^= (dfs(edge[u][i])+1);
}
return ans;
}
int main(){
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i = 0;i < n; i++){
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].r);
p[i].x += 20000;
p[i].y += 20000;
}
init();
cnt++;
build(1,0,40000);
sort(p,p+n,comp);
memset(in,0,sizeof(in));
for(int i = 0;i < maxn; i++){
head[i].clear();
edge[i].clear();
}
for(int i = 0;i < n; i++){
query(1,0,40000,i);
add(1,0,40000,p[i].x,i);
}
int ans = 0;
for(int i = 0;i < n; i++){
if(in[i] == 0){
int u = dfs(i);
ans ^=(u+1);
}
}
if(ans == 0)
cout<<"Bob"<<endl;
else
cout<<"Alice"<<endl;
}
return 0;
}
扫描线方法的代码如下:
详细看我的博客,介绍圆的扫描线http://blog.csdn.net/firenet1/article/details/47041145
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<set>
#include<cstring>
#include<vector>
#include<math.h>
using namespace std;
#define maxn 100010
struct Circle{
int id,x,r,y;
Circle(int _id=0,int _x=0,int _y=0){
id=_id, x=_x, y=_y;
}
};
Circle cir[maxn];
//用于对圆的左右端点排序
Circle p[maxn];
int cmp(Circle a,Circle b){
return a.x < b.x;
}
//用于扫面的位置排序,globalx是当前扫描线的位置
int globalx;
//计算圆id在x=globalx时的y坐标
double yposition(int id,int ty){
double x = globalx - cir[id].x;
double y = sqrt(cir[id].r*1.0*cir[id].r-x*x);
if(ty == 1) return y+cir[id].y;
return cir[id].y-y;
}
//记录扫描线的交点信息ty = 1表示上交点
struct Point{
int id,ty;
Point(int _id=0,int _ty=0){
id = _id;
ty = _ty;
}
//扫描线与圆的交点按y从大到小排序函数
bool operator < (const Point & b)const{
if(id == b.id)
return ty > b.ty;
return yposition(id,ty) > yposition(b.id,b.ty);
}
};
set<Point> haha;
vector<int>head[maxn];
int fa[maxn];
int dfs(int u){
int ans = 0;
for(int i = 0;i < head[u].size(); i++)
ans ^= (dfs(head[u][i]) + 1);
return ans;
}
int main(){
int n,f,t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i = 0;i < n; i++){
scanf("%d%d%d",&cir[i].x,&cir[i].y,&cir[i].r);
p[i*2] = Circle(i,cir[i].x-cir[i].r,0);
p[i*2+1] = Circle(i,cir[i].x+cir[i].r,1);
}
for(int i = 0;i <= n; i++)
head[i].clear();
int nn = 2 * n;
sort(p,p+nn,cmp);
haha.clear();
set<Point>::iterator it1,it2;
for(int i = 0;i < nn; i++){
globalx = p[i].x;
if(p[i].y == 1){
haha.erase(Point(p[i].id,0));
haha.erase(Point(p[i].id,1));
}
else {
it1 = haha.insert(Point(p[i].id,1)).first;
it2 = it1++;
if(it1 == haha.end() || it2 == haha.begin())
f = n;
else {
it2--;
if(it2->id == it1->id)
f = it1->id;
else if(fa[it1->id] == it2->id)
f =it2->id;
else if(fa[it2->id] == it1->id)
f = it1->id;
else
f = fa[it1->id];
}
haha.insert(Point(p[i].id,0));
head[f].push_back(p[i].id);
fa[p[i].id] = f;
}
}
int ans = dfs(n);
if(ans == 0)
printf("Bob\n");
else
printf("Alice\n");
}
return 0;
}