HDU 5724 博弈,SG函数

来源:互联网 发布:蛙5火箭知乎 编辑:程序博客网 时间:2024/06/04 23:23

http://acm.hdu.edu.cn/showproblem.php?pid=5724


题意:20列n行的一个棋盘,起始上面有一些棋子,每次玩家可以移动向右,如果右边有连续x个就跳过。。问玩家一输赢情况。。


思路:发现和SG函数那个图的模型很像,所以联想到SG函数可以。。(玄学。。我并不懂博弈)。。那么我们就可以按照SG函数的定义,用mex那个操作来记忆化搜索一下,过程基本上就是一个状压DP,当然也可以倒着递推啦。。复杂的大概1e7.。

(核心思路就是想到SG函数,使用记忆化搜索的方法求出所有状态的SG值,然后就愉快的异或一下子。。)


代码:

#include <iostream>#include <cmath>#include <cstdio>#include <cstring>using namespace std;int ans[(1<<20)+5];int vis[(1<<20)+5];int mov(int sit,int idx){    int nxt=sit&(~(1<<idx));    idx--;    while(idx>=0&&(sit&(1<<idx))) idx--;    if(idx<0) return -1;    nxt=(nxt|(1<<idx));    return nxt;}int dfs(int sit){    vis[sit]=1;    int mex[21]={0};    for(int i=0;i<20;i++){        if(sit&(1<<i)){            int nxt=mov(sit,i);            if(nxt!=-1){                if(vis[nxt]==1) mex[ans[nxt]]=1;                else mex[dfs(nxt)]=1;            }        }    }    for(int i=0;i<21;i++){        if(!mex[i]) return ans[sit]=i;    }}int main(){    int sit=0;    ans[0]=0;    for(int i=19;i>=0;i--){        sit=sit|(1<<i);        dfs(sit);    }    int t;    scanf("%d",&t);    while(t--){        int n,m,idx;        int ret=0;        scanf("%d",&n);        for(int i=0;i<n;i++){            scanf("%d",&m);            int st=0;            for(int j=0;j<m;j++){                scanf("%d",&idx);                st|=(1<<(20-idx));            }            ret^=ans[st];        }        if(ret==0)            printf("NO\n");        else            printf("YES\n");    }    return 0;}



0 0
原创粉丝点击