Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2235 | Accepted: 699 |
Description
Harry and Sally were playing games at Christmas Eve. They drew some Christmas trees on a paper:
![](https://i-blog.csdnimg.cn/blog_migrate/817a91dd7d0d3df2e6e91f34a50235cf.png)
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:
![](https://i-blog.csdnimg.cn/blog_migrate/57cd3715cec08ae873b005a96790bed8.png)
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:
![](https://i-blog.csdnimg.cn/blog_migrate/928bedb08ec04b15d29bec07741600d9.png)
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:
![](https://i-blog.csdnimg.cn/blog_migrate/9de01744be1a44b0c1822e1b5cae5e82.png)
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
思路:树上删边博弈,叶节点的SG值为0,内部节点的SG为其所有子树的SG+1之后的异或。关键在于,这里最初给的图并不是树,可能会存在环,这里用一个定理:
Fusion Principle:
我们可以对无向图做如下改动:将图中的任意一个偶环缩成一个新点,任意一个奇环缩成一个新点加一个新边;所有连到原先环上的边全部改为与新点相连。这样的改动不会影响图的SG值。
所以可以用Tarjan求联通分量,然后对其标记即可,这里可能最后形成的是森林,我们只要将所有数的SG异或就是答案了。#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
const int MAXN = 105;
int n, m, dfs_num = 0, top = 0; // dfs序
int dfn[MAXN], low[MAXN]; // Tarjan 参量
bool instack[MAXN]; // 判断节点是否在栈中
bool mark[MAXN]; // 把环中的点标记,压缩环, true 标记为压缩
int sta[MAXN]; // Tarjan 栈
vector<int> linker[MAXN]; // 邻接表
int mat[MAXN][MAXN]; // 存放边的数量
void Init() {
dfs_num = top = 0;
for(int i = 0; i <= n; ++i) {
linker[i].clear();
}
for(int i = 0; i <= n; ++i) {
for(int j = 0; j <= n; ++j) {
mat[i][j] = 0;
}
instack[i] = mark[i] = sta[i] = dfn[i] = low[i] = 0;
}
}
void Tarjan(int u, int pre) {
dfn[u] = ++dfs_num; // dfs 序
low[u] = dfs_num; // x或者x的子树能够追溯道德最早栈中节点的次序号
instack[u] = true; // 在栈中
sta[top++] = u; // 入栈
for (int i = 0; i < linker[u].size(); ++i) {
int v = linker[u][i];
if(pre == v && mat[u][v] > 1) {
if(mat[u][v] % 2 == 0) { // 判断重边
mark[u] = true; // pre为u父节点, u -> v有重边,如果是偶数,直接压缩为一个点
continue;
}
}
if (!dfn[v]) { // 第一次遍历v
Tarjan(v, u);
low[u] = min(low[u], low[v]);
} else if (v != pre && instack[v]){ // 回溯遍历v时,v是u的子树并且在栈中
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u]) { // 存在强连通分量的条件
int cnt = 1;
top--;
while(sta[top] != u) { // 等于u时推出
mark[sta[top--]] = true;
cnt++;
}
if(cnt && (cnt & 1)) { // 如果节点为奇数,则保留一个点,包括x,也就是两个点,保留一条边
mark[sta[top+1]] = false;
}
}
}
int getSg(int u, int pre) { // 树上删边博弈
int ret = 0;
for(int i = 0; i < linker[u].size(); ++i) {
if(!mark[linker[u][i]] && linker[u][i] != pre) {
ret ^= (getSg(linker[u][i], u) + 1);
}
}
return ret;
}
int main() {
int T;
while(cin >> T) {
int ans = 0;
while(T--) {
Init();
cin >> n >> m;
int u, v;
for(int i = 0; i < m; ++i) {
cin >> u >> v;
linker[u].push_back(v);
linker[v].push_back(u);
mat[u][v]++;
mat[v][u]++;
}
Tarjan(1, -1);
ans ^= getSg(1, -1);
}
cout << (ans ? "Sally" : "Harry") << endl;
}
return 0;
}