POJ 3710 Christmas Game

Harry and Sally were playing games at Christmas Eve. They drew some Christmas trees on a paper:

Then they took turns to cut a branch of a tree, and removed the part of the tree which had already not connected with the root. A step shows as follows:

Sally always moved first. Who removed the last part of the trees would win the game.

After a while, they all figured out the best strategy and thought the game was too simple for them. Harry said, “The Christmas trees should have some gifts in them!” So Sally drew some gifts (simple polygons) in the initial trees:

You may assume the initial picture is a tree with some simple polygons, in which each edge is involved in at most one polygon. We also know that every polygon has only one node involved in the main tree (the hanging point of the giftJ) .In every sub-tree (connected subgraph), there was one and only one node representing the “root”. According to these assumptions, following graphs will never appear:

Sally and Harry took turns (Sally was always the first person to move), to cut an edge in the graph, and removed the part of the tree that no longer connected to the root. The person who cannot make a move lost the game.

Your job is to decide who will finally win the game if both of them use the best strategy.

Input

The input file contains multiply test cases.
The first line of each test case is an integer N (N<100), which represents the number of sub-trees. The following lines show the structure of the trees. The first line of the description of a tree is the number of the nodes m (m<100) and the number of the edges k (k<500). The nodes of a tree are numbered from 1 to m. Each of following lines contains 2 integers a and b representing an edge <a, b>. Node 1 is always the root.

Output

For each test case, output the name of the winner.

Sample Input
2
2 1
1 2
4 4
1 2
2 3
2 4
3 4
Sample Output
Sally
Hint

The sample graph is

题意:
  • 有 N个局部联通的图。
  • Harry 和 Sally轮流从图中删边,删去一条边后,不与根节点相连的部分将被移走。Sally为先手。
  • 图是通过从基础树中加一些边得到的。
  • 所有形成的环保证不共用边,且只与基础树有一个公共点。
  • 谁无法移动谁输。
这题与树上删边游戏很像,只不过加上了环
根据克朗原理,一个以x为根的子树可以视为一颗"竹子"
竹子长度为所有分支边数异或和$len[x]=len[v_1] xor len[v_2]...$
一颗竹子上的树删边游戏可以视为Nim游戏,所以SG[len]=len
相当于$SG[x]=SG[v_1] xor SG[v_2]....$
考虑把环转化:(环的根为x)
当环的边数为奇数时:
任意删一条边,那么x的2个支链必定同奇偶
那么SG异或值显然为偶数
那么SG[x]=1,等价与把奇环缩成一个新点
边数为偶数时
SG异或值为奇数
SG[x]=0,等价与把偶环去掉
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 struct Node
 8 {
 9   int next,to;
10 }edge[2001];
11 int head[105],num,SG[105],stack[105],top,n,m,ans;
12 int vis[105];
13 void add(int u,int v)
14 {
15   num++;
16   edge[num].next=head[u];
17   head[u]=num;
18   edge[num].to=v;
19 }
20 void dfs(int x,int pa)
21 {int i,now,cnt,flag;
22   vis[x]=1;
23   stack[++top]=x;
24   flag=0;
25   for (i=head[x];i;i=edge[i].next)
26     {
27       int v=edge[i].to;
28       if (v==pa&&flag==0)
29     {
30       flag=1;
31       continue;
32     }
33       if (vis[v]==1)
34     {
35       now=stack[top];cnt=1;
36       while (now!=v)
37         {
38           cnt++;
39           vis[now]=0;
40           now=stack[--top];
41         }
42       if (cnt%2==1)
43         SG[v]^=1;
44     }
45       else if (vis[v]==-1)
46     {
47       dfs(v,x);
48       if (vis[v]) SG[x]^=(1+SG[v]);
49     }
50     }
51   if (vis[x]) top--;
52 }
53 int main()
54 {int N,i,j,u,v;
55   while (cin>>N)
56     {
57       ans=0;
58       for (j=1;j<=N;j++)
59     {
60       scanf("%d%d",&n,&m);
61       memset(head,0,sizeof(head));
62       memset(SG,0,sizeof(SG));
63       memset(vis,-1,sizeof(vis));
64       num=0;top=0;
65       for (i=1;i<=m;i++)
66         {
67           scanf("%d%d",&u,&v);
68           add(u,v);
69           add(v,u);
70         }
71       dfs(1,0);
72       ans^=SG[1];
73     }
74       if (ans) printf("Sally
");
75       else printf("Harry
");
76     }
77 }
原文地址:https://www.cnblogs.com/Y-E-T-I/p/8438446.html