jzoj3819 取石子

本文深入探讨了一种基于博弈论的游戏算法实现,通过分析不同情况下玩家的最优策略选择,提出了利用记忆化搜索来解决复杂博弈问题的方法,并给出了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

这里写图片描述

Solution

这道题在考场上做的时候特别有思路 但还是没有做出来
我们考虑每一堆都大于1的情况
我们发现合并的本质就是在保证数量不变的情况下切换先后手
所以,如果堆数-1+石子总数为偶数则后手胜,为奇数则先手胜
再来考虑有1的情况
这个时候如果要分类讨论就会变得相当复杂
所以我们考虑记忆化搜索
设一个状态 a[x][y]表示为1的有x堆,剩下的石子堆的操作总数为y(y=堆数+总数-1)
然后仔细分类转移即可
具体可以看代码

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int n,t,fl,x,y,i,a[60][50005],v[60][50005],aa[60],sum;
int read(){
    int sum=0;
    char c=getchar();
    while (c<'0'||c>'9') c=getchar();
    while (c>='0'&&c<='9'){
        sum=sum*10+c-'0';
        c=getchar();}
    return sum;
}
inline bool dfs(int x,int y){
    if (!x) return (y&1);
    if (y==1) return dfs(x+1,0);
    if (v[x][y]) return a[x][y];
    v[x][y]=1;
    if (x>=2&&y&&!dfs(x-2,y+3)) {
        a[x][y]=1;
        return 1;}
    if (x>=2&&!y&&!dfs(x-2,y+2)){
        a[x][y]=1;
        return 1;}
    if (x&&y&&!dfs(x-1,y+1)){
        a[x][y]=1;
        return 1;}
    if (y&&!dfs(x,y-1)){
        a[x][y]=1;
        return 1;
    }
    if (x&&!dfs(x-1,y)){
        a[x][y]=1;
        return 1;
    }
    a[x][y]=0;
    return 0;
}
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    t=read();
    while (t){
        t--;
        fl=1;
        sum=0;
        n=read();
        fo(i,1,n){
            aa[i]=read(),sum+=aa[i];
            if (aa[i]==1) fl=0;}
        if (fl) if ((sum+n-1)&1) printf("YES\n"); else printf("NO\n");
           else {
             x=0,y=0;
             fo(i,1,n) if (aa[i]==1) x++; else y+=aa[i]+1;
             if (dfs(x,max(y-1,0))) printf("YES\n"); else printf("NO\n"); 
           }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值