如果知道树的删边游戏的话,这道题应该是很好做的。
树的删边游戏规则如下:
1.给出一颗n个结点的树,其中有一个点规定为根。
2.两名游戏者轮流操作,每次从树中删去一条边,删去该边后,不与根节点连通的部分将被移走。
3.无法操作者输。
定理:
1.叶子结点的sg值为0;
2.分支结点的sg值为其所有子节点的sg值加1后的异或和。
有了这些知识以后就可以做了,设0结点为根,求其sg值即可。
暴力建边代码:
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 7 const int N = 11111; 8 int head[N]; 9 int e; 10 11 struct Edge 12 { 13 int v, next; 14 } edge[N]; 15 16 void addEdge( int u, int v ) 17 { 18 edge[e].v = v; 19 edge[e].next = head[u]; 20 head[u] = e++; 21 } 22 23 struct Circle 24 { 25 int x, y, r; 26 bool operator < ( const Circle & o ) const 27 { 28 return r < o.r; 29 } 30 } circle[N]; 31 32 int dfs( int u ) 33 { 34 int res = 0; 35 for ( int i = head[u]; i != -1; i = edge[i].next ) 36 { 37 res ^= ( dfs( edge[i].v ) + 1 ); 38 } 39 return res; 40 } 41 42 bool involve( int i, int j ) 43 { 44 int x1 = circle[i].x, x2 = circle[j].x; 45 int y1 = circle[i].y, y2 = circle[j].y; 46 int r1 = circle[i].r, r2 = circle[j].r; 47 return ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 ) < ( r1 - r2 ) * ( r1 - r2 ); 48 } 49 50 int main () 51 { 52 int t; 53 scanf("%d", &t); 54 while ( t-- ) 55 { 56 int n; 57 scanf("%d", &n); 58 for ( int i = 1; i <= n; i++ ) 59 { 60 scanf("%d%d%d", &circle[i].x, &circle[i].y, &circle[i].r); 61 } 62 e = 0; 63 memset( head, -1, sizeof(head) ); 64 sort( circle + 1, circle + 1 + n ); 65 for ( int i = 1; i <= n; i++ ) 66 { 67 bool flag = false; 68 for ( int j = i + 1; j <= n; j++ ) 69 { 70 if ( involve( i, j ) ) 71 { 72 addEdge( j, i ); 73 flag = true; 74 break; 75 } 76 } 77 if ( !flag ) 78 { 79 addEdge( 0, i ); 80 } 81 } 82 int ans = dfs(0); 83 if ( ans ) puts("Alice"); 84 else puts("Bob"); 85 } 86 return 0; 87 }