POJ 3710:Christmas Game

Posted yuzao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3710:Christmas Game相关的知识,希望对你有一定的参考价值。

Description

在树上挂几个环,每一个环只与树有一个公共点,环与环之间无公共边,每次删掉一条边,把不与根节点相连的部分删除,不能操作者输,问是否先手必胜。
题面

Solution

由于环是在叶子上的,所以这个环可以单独考虑
假设这个环是奇环,那么砍掉任意一条边之后,就会变成从叶子节点延伸出来的两条链,且这两条链奇偶性相同,所以后继状态的 (SG) 异或起来不可能为奇数,并且可以为 (0),所以 (SG=mex(SG[u])=1)
假设这个环是偶环,那么这两条链的奇偶性不同,所以异或起来的所有情况中一定没有 (0),所以 (SG=mex=0)
那么我们就可以把环缩成一个点了
假设是偶环,实际上就没有贡献了,直接把它去掉就可以了
假设是奇环,那么会有 (1) 的贡献,我们直接在这个叶子节点后面接上一个点就可以达到这样的效果了

那么现在问题就转化为了树上删边游戏,利用结论:节点 (x)(SG) 等于所有儿子 (u)((SG[u]+1)) 的异或和
这样就推出了根节点的 (SG)
因为有很多棵树,再把所有根节点的 (SG) 异或起来就行了

还有就是这个题仿佛是可以有点双的?

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
using namespace std;
const int N=2010;
int n,m,T,sz[N],head[N],to[N*2],nxt[N*2],num=1;bool vis[N];
int dfn[N],low[N],DFN=0,st[N],top=0,sum,q[N],r=0;
inline void Clear(){
    num=1;DFN=sum=0;
    for(register int i=0;i<N;i++)sz[i]=head[i]=dfn[i]=low[i]=vis[i]=0;
}
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline void tarjan(int x,int last){
    dfn[x]=low[x]=++DFN;st[++top]=x;
    for(int i=head[x];i;i=nxt[i]){
        if(i==last || to[i]>n)continue;
        int u=to[i];
        if(!dfn[u]){
            tarjan(u,i^1),low[x]=min(low[x],low[u]);        
            if(low[u]>=dfn[x]){
                int sz=2;r=0;
                while(top && st[top]!=u)q[++r]=st[top--],sz++;
                if(top)q[++r]=st[top--];
                if(sz>2)while(r)vis[q[r--]]=1;
                if(sz>2 && (sz&1))link(x,++sum);
            }
        }
        else low[x]=min(low[x],dfn[u]);
    }
}
inline int dfs(int x,int last){
    int ret=0;
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        if(u==last || vis[u])continue;
        ret^=(dfs(u,x)+1);
    }
    return ret;
}
inline int work(){
    Clear();
    int x,y;
    scanf("%d%d",&n,&m);sum=n;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        link(x,y);link(y,x);
    }
    tarjan(1,0);
    return dfs(1,1);
}
int main(){
    freopen("pp.in","r",stdin);
    freopen("pp.out","w",stdout);
    while(~scanf("%d",&T)){
        int ans=0;
        while(T--)ans^=work();
        if(ans)puts("Sally");
        else puts("Harry");
    }
    return 0;
}

以上是关于POJ 3710:Christmas Game的主要内容,如果未能解决你的问题,请参考以下文章

poj 3710 Christmas Game(树上的删边游戏)

poj 3710 Christmas Game

POJ 3710 Christmas Game#经典图SG博弈

POJ 3710:Christmas Game

poj2234 Matches Game

[POJ 1463] Strategic Game