【codevs3153】【BZOJ3895】取石子游戏,博弈论之记忆化搜索

传送门1
传送门2(权限)


思路:
之前模拟赛的一道题
当时在硬刚T1的正解,而没有写暴力
考虑局面没有石子堆是1的情况
那么显然只考虑总数的奇偶就可以判断答案了
因为必胜方拼命合并石子堆,必败方即使把一个堆减到1个石子,也会被必胜方拿走(就只有这一个石子时)或合并到另一个堆中去
所以局面除此之外只会被石子数为1的堆所影响(它被直接拿掉实际上是一步完成了合并,拿走两步操作)
设f[x][y]表示有x个石子数为1的堆,石子数大于1的堆的石子总数为y
通过记忆化搜索解决问题
注意状态转移时要细致讨论
代码:

#include<cstdio>
#include<cstring>
using namespace std;
int T,n,m;
int f[55][50055],a[50055];
bool vis[55][50055];
int in()
{
    int t=0;char ch=getchar();
    while (ch>'9'||ch<'0') ch=getchar();
    while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();
    return t;
}
int dfs(int x,int y)
{
    if (!vis[x][y]) vis[x][y]=1;
    else return f[x][y];
    if (y==1) return f[x][y]=dfs(x+1,0);
    if (x-1>=0&&!dfs(x-1,y)) return f[x][y]=1;
    if (x-2>=0&&!dfs(x-2,y+2+(y>0))) return f[x][y]=1;
    if (y>1&&!dfs(x,y-1)) return f[x][y]=1;
    if (x-1>=0&&y&&!dfs(x-1,y+1)) return f[x][y]=1;
    return 0;
}
main()
{
    memset(vis,0,sizeof(vis));
    for (T=in();T;--T)
    {
        n=in();
        int x=0,y=0;
        for (int i=1;i<=n;++i)
        {
            a[i]=in();
            if (a[i]==1) ++x;
            else y+=a[i]+1;
        }
        if (y) --y;
        dfs(x,y);
        if (f[x][y]) puts("YES");
        else puts("NO");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值