HDU5724


题意

一个 n * 20 的棋盘,棋盘上有若干棋子,Alice 和 Bob 轮流走,
每人每次可以选择任一行的一颗棋子向右移动到最近的一个空格 ;
也就是说如果右边与它相邻的格子里没有棋子,就移到右边与他相邻的格子去;
如果右边与它相邻的格子里 有棋子,就跳过它们移到相邻的空格 ;
一个空格只能放一颗棋子,且不能够放出去。
双方都采取最优策略,最后不能移动棋子的一方输 。

 

 

输入:
第一行输入 t ,表 t 组数据;
第二行输入 n ,表示 棋盘有 n 行;
接下来 n 行,每行包括 m (表示此行有 m 个棋子 )和 m 个数(棋子的位置)

 

输出:
若 Alice 赢,输出“YES” ,否则“NO”。

 

 

解题:

把它看成由 n 个子游戏组成的游戏, 那么整个游戏的 sg 值就是所有子游戏的 sg 值异或起来。
用二进制表示每一行的游戏局面 。 写完这题 感觉对状态压缩又多了解了一点点~~

(写的时候SB了一下,sg数组开小了= = 不造错哪又纠结了很久,不过也因为这样,想了很久这个问题,印象更深刻= =)

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
using namespace std;
const int maxn = 1050000;
int num[25],sg[maxn];
void getsg()
{
    for(int i=1;i<(1<<20);i++)
    {
        int hash[50] = {0}, r=-1;
        for(int j=0;j<20;j++){
            if( !((i>>j) & 1)) r = j;
            if( (i>>j) & 1){
                if(r != -1)
                hash[ sg[i ^ (1<<j) ^ (1<<r)]] = 1;
            }
        }
        int j = 0;
        while(hash[j]!=0) j++;
        sg[i] = j; 
    }
}
int main()
{
    int t,n,m,loc; 
    getsg(); 
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n); 
        int ans = 0;
        for(int i=0;i<n;i++){
            scanf("%d",&m);   
            num[i] = 0;   
            for(int j=0;j<m;j++){
                scanf("%d",&loc);
                num[i] ^=  (1<<(20-loc));  
            }
            ans ^= sg[ num[i] ];
        }
        printf(ans?"YES\n":"NO\n");
    }
    return 0;
}

 

posted @ 2016-07-30 13:58  Ember  阅读(298)  评论(2编辑  收藏  举报