博弈论合集

hdu 1847

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int dp[1003];
int main()
{
    int p[30];
    p[0]=1;
    for(int i=1;i<20;i++){
        p[i]=p[i-1]<<1;
    }
    memset(dp,0,sizeof(dp));
    dp[0]=0;dp[1]=1;
    dp[2]=1;
    for(int i=3;i<1003;i++){
        for(int j=0;j<20;j++){
            if(p[j]<=i){
                if(dp[i-p[j]]==0)dp[i]=1;
            }
        }
    }
    int n;
    while(scanf("%d",&n)!=EOF){
        dp[n]==0?printf("Cici\n"):printf("Kiki\n");
    }

    return 0;
}

hdu 1848


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <set>
using namespace std;
int sg[1045];
int f[100];

void grundy(){
    sg[0]=0;
    for(int j=1;j<=1000;j++){
        set<int >s;
        for(int i=1;i<20;i++){
            if(f[i]<=j)s.insert(sg[j-f[i]]);
        }
        int g=0;
        while(s.count(g))g++;
        sg[j]=g;
    }
}

int main()
{
    f[0]=1;
    f[1]=1;
    f[2]=2;
    for(int i=3;i<20;i++){
        f[i]=f[i-1]+f[i-2];
    }
    grundy();
    int n,m,p;
    while(~scanf("%d%d%d",&n,&m,&p)){
        if(!n&&!m&&!p)break;
        string ans=(sg[n]^sg[m]^sg[p])==0?"Nacci":"Fibo";
        cout<<ans<<endl;
    }
    return 0;
}

hdu 5724

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <set>
#include <cstring>
using namespace std;

int sg[1100000];
int s[30];
void grundy(){
    sg[0]=0;
    for(int i=1;i<(1<<20);i++){
        memset(s,0,sizeof(s));
        for(int j=0;j<20;j++){
            if(i&(1<<j)){
                for(int k=j;k>=0;k--){
                    if(!(i&(1<<k))){
                        s[sg[( (i^(1<<j) )|(1<<k))]]=1;
                        break;
                    }
                }
            }
        }
        for(int j=0;j<30;j++){
            if(s[j]==0){
                sg[i]=j;break;
            }
        }
    }
}


int main()
{
    grundy();
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        int ans=0;
        for(int i=0;i<n;i++){
            int m;
            scanf("%d",&m);
            int tmp=0;
            for(int j=0;j<m;j++){
                int z;
                scanf("%d",&z);
                tmp|=1<<(20-z);
            }
            ans^=sg[tmp];
        }
        if(ans)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}


hdu 1809

这道题目我一定要好好吐槽一下,二维char数组表示成一维string,用来表示状态,然后求sg函数值用记忆化搜索,然后就一直WA,心好累差点怀疑人生,QAQ。后来发现记忆化搜索代码加上 if(vis[str])return sg[str]; 就WA,所以肯定这里出问题,后来一想,这种状态表示有毒,例如5x4与4x5的矩阵显然不同,但是展开成一维string时显然可以得到相同string,所以二维展一维时除了内容,还要加上R,C两个参数。可是这样就要用结构体,想想acm中处理字符串的技巧,其实在二维数组表示成string时,在末尾加上一个区别的符号就行了。这样就可以写最正宗的记忆化搜索了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <cstring>
using namespace std;
char g[55][55];
map<string,int>sg;
map<string,int>vis;
string ss;
int R,C;
string tostr(){
    ss="";
    for(int i=0;i<R;i++){
        ss+=g[i];
        ss+='*';
    }
    return ss;
}
int grundy(){
    string str=tostr();//cout<<str<<endl;
    if(vis[str])return sg[str];
    int s[100];
    memset(s,0,sizeof(s));
    for(int i=1;i<R;i++){
        for(int j=1;j<C;j++){
            if(g[i][j]=='0'&&g[i-1][j]=='0'&&g[i][j-1]=='0'&&g[i-1][j-1]=='0'){
                g[i][j]='1';g[i-1][j]='1';g[i][j-1]='1';g[i-1][j-1]='1';
                s[grundy()]=1;
                g[i][j]='0';g[i-1][j]='0';g[i][j-1]='0';g[i-1][j-1]='0';
            }
        }
    }
    int k=0;
    while(s[k])k++;
    vis[str]=1;
    sg[str]=k;
    return k;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF){
        int ans=0;
        for(int i=0;i<n;i++){
            scanf("%d%d",&R,&C);
            for(int j=0;j<R;j++)scanf("%s",g[j]);
            ans^=grundy();
        }
        printf("%s\n",ans?"Yes":"No");
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值