POJ3710 Christmas Game(Tarjan+Nim博弈论)

解析一款圣诞主题的游戏,玩家需在树形结构上进行操作,通过剪断边并移除未连接根部的部分来竞争,利用特定策略确定胜者。

Christmas Game

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 2702 Accepted: 871

Description

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 <ab>. 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棵树两人轮流剪去一条边并且把与根不相连的边全部去除,问谁胜利了!

题解:这有一个定理:那就是中间节点的sg值为所有叶子节点的sf值加1再异或起来,相关证明请参考算法合集之《组合游戏略述——浅谈SG游戏的若干拓展及变形》

这里可以找到规律当环的边数为奇时子树的根节点的sg值是1

当为偶数是子树根节点为0;

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
#define ps(a)     push(a)
#define clr(a,b)  memset(a,b,sizeof(a))
const int maxn=505;
struct Edge
{
    int y,next;
}g[maxn];
int m,k,e,head[maxn],vis[maxn];
int tot,loop[maxn],dfn[maxn];
void adde(int a,int b)
{
   g[++e].y=b;
   g[e].next=head[a];head[a]=e;
}
stack<int> sa;
void  Tarjan(int x,int pre,int dep)
{
    dfn[x]=dep;
    sa.ps(x);vis[x]=1;
    for(int i=head[x];i!=0;i=g[i].next)
    {
        int y=g[i].y;
        if(y==pre){continue;}
        if(!vis[y])
        {
            Tarjan(y,x,dep+1);
        }
        else if(loop[y]==0)
        {
            while(sa.top()!=y)
            {
                int tm=sa.top();sa.pop();
                loop[tm]=1;
                if(sa.top()==y&&(dfn[x]-dfn[y]+1)%2){loop[tm]=0;}
            }
        }
    }
    return ;
}
int get_sg(int x,int pre)
{
    int ret=0;
    for(int i=head[x];i!=0;i=g[i].next)
    {
        if(g[i].y==pre||loop[g[i].y]){continue;}
        ret^=(1+get_sg(g[i].y,x));
    }
    return ret;
}
int main()
{
    #ifndef ONLINE_JUDGE
   // freopen("data.txt","r",stdin);
    #endif
    int n;
    while(~scanf("%d",&n))
    {
        int ret=0;
        while(n--)
        {
         clr(head,0);clr(vis,0);
         clr(loop,0);clr(dfn,0);
         e=0;tot=0;
         scanf("%d%d",&m,&k);
         while(k--)
         {
             int a,b;
             scanf("%d%d",&a,&b);
             adde(a,b);adde(b,a);
         }
         Tarjan(1,0,1);
         ret^=get_sg(1,0);
        }
         puts(ret?"Sally":"Harry");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值