HUSTOJ 1612 A new tree game(树删边博弈)

题目链接:http://acm.hust.edu.cn/problem.php?id=1612

题意:每个树枝被砍K次后,不与树根相连的部分会被删掉。求先砍的是否能赢。

思路:下面证明:设AB之间的边被砍K次后G‘会被删掉。则有:

(1)K=1,则SG(G)=SG(G')+1;

(2)K为偶数,则SG(G)=SG(G');

(3)k大于1且为奇数,则SG(G)=SG(G')^1。

HUSTOJ 1612 A new tree game(树删边博弈)

数学归纳法:

(1)一个节点和两个节点的显然成立;

(2)设n个节点的成立。K=1时不再推导。K为偶数时,G的两个子状态为,要么在G’上砍一刀,SG为[0,SG[G']-1],要么在AB边砍一刀,此时,若AB边还能砍1刀,则此子状态SG为SG[SG']+1,否则为SG[G']^1,不管怎样都有,SG[G]=SG[G'];K为大于1的奇数时,和刚才类似,在G'上砍一刀,该子状态的SG为[0,SG[G']-1]^1,在AB上砍一刀,该子状态SG为SG[G'],这时,SG[G]=SG[G']^1。





int C;

int n,SG[MAX][3];

vector<int> a[MAX];



void DFS(int u,int pre)

{

    int i,v;

    for(i=0;i<SZ(a[u]);i++)

    {

        v=a[u][i];

        if(v==pre) continue;

        DFS(v,u);

        SG[u][0]^=SG[v][0]+1;

        SG[u][1]^=SG[v][1]^1;

        SG[u][2]^=SG[v][2];

    }

}



int main()

{

    for(scanf("%d",&C);C--;)

    {

        scanf("%d",&n);

        int i,x,y;

        for(i=0;i<=n;i++) a[i].clear();

        for(i=1;i<n;i++)

        {

            scanf("%d%d",&x,&y);

            a[y].pb(x),a[x].pb(y);

        }

        clr(SG,0);

        DFS(0,-1);

        int Q,ans;

        for(scanf("%d",&Q);Q--;)

        {

            scanf("%d",&i);

            if(i==1) ans=SG[0][0];

            else if(i&1) ans=SG[0][1];

            else ans=SG[0][2];

            if(ans) puts("tclsm");

            else puts("littleSheep");

        }

    }

    return 0;

}

  

 

你可能感兴趣的:(tree)