思路:首先用Tarjan算法找出树中的环,环为奇数变为边,为偶数变为点。
之后用博弈论的知识:某点的SG值等于子节点+1后的异或和。
代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<vector> 6 #include<cstring> 7 using namespace std; 8 int ans; 9 vector<int>p[105]; 10 bool vis[105],inss[105]; 11 int low[105],dfa[105],num[105][105],ss[105],top; 12 void Tarjan(int u,int pre,int d) 13 { 14 low[u]=dfa[u]=d; 15 ss[top++]=u; 16 inss[u]=1; 17 for(int i=0;i<p[u].size();i++){ 18 int v=p[u][i]; 19 if(v==pre&&num[u][v]>1){ 20 if(num[u][v]%2==0) vis[u]=1; 21 continue; 22 } 23 if(!dfa[v]){ 24 Tarjan(v,u,d+1); 25 low[u]=min(low[u],low[v]); 26 } 27 else if(v!=pre&&inss[v]){ 28 low[u]=min(low[u],dfa[v]); 29 } 30 } 31 if(low[u]==dfa[u]){ 32 top--; 33 int cnt=1; 34 while(ss[top]!=u){ 35 vis[ss[top--]]=1; 36 cnt++; 37 } 38 if(cnt&1) vis[ss[top+1]]=0; 39 } 40 } 41 int dfs(int d,int pre) 42 { 43 int ans=0; 44 for(int i=0;i<p[d].size();i++){ 45 if(p[d][i]!=pre&&!vis[p[d][i]]) 46 ans^=(1+dfs(p[d][i],d)); 47 } 48 return ans; 49 } 50 int main() 51 { 52 int n,m,a,b,t,ans; 53 while(scanf("%d",&t)!=EOF){ 54 ans=0; 55 while(t--){ 56 memset(vis,0,sizeof(vis)); 57 memset(ss,0,sizeof(ss)); 58 memset(low,0,sizeof(low)); 59 memset(dfa,0,sizeof(dfa)); 60 memset(num,0,sizeof(num)); 61 memset(inss,0,sizeof(inss)); 62 scanf("%d%d",&n,&m); 63 for(int i=0;i<=n;i++) p[i].clear(); 64 while(m--){ 65 scanf("%d%d",&a,&b); 66 num[a][b]++; 67 num[b][a]++; 68 p[a].push_back(b); 69 p[b].push_back(a); 70 } 71 top=0; 72 Tarjan(1,-1,1); 73 ans^=dfs(1,-1); 74 } 75 puts(ans?"Sally":"Harry"); 76 } 77 return 0; 78 }