1 条题解

  • 0
    @ 2025-5-8 10:51:11

    解题思路:

    这是一个博弈论问题,关键在于确定每个石子数的必胜态或必败态。我们可以使用动态规划来解决:

    定义状态:

    dp[s]dp[s] 表示剩余ss个石子时,当前玩家是否有必胜策略(11表示必胜,00表示必败)。

    状态转移:

    对于当前石子数ss,当前玩家可以取11MiMi个石子(MiMi是当前玩家的最大取石子数)。

    如果存在某个kk11kkMiMi),使得dp[sk]dp[s - k]为必败态(即dp[sk]dp[s - k] = 00),则当前玩家可以必胜(dp[s]dp[s] = 11)。

    否则,当前玩家必败(dp[s]dp[s] = 00)。

    玩家轮换:

    玩家按顺序轮流取石子,因此当前玩家的编号可以通过轮次计算currentplayer=(s1)(current_player = (s - 1) % (2 * n))

    初始条件:

    dp[0]dp[0] = 00:没有石子可取时,当前玩家输。

    解题方法:

    动态规划表初始化:

    初始化dpdp数组,大小为SS + 11,初始值为00

    填充动态规划表:

    对于每个石子数ss11SS

    计算当前玩家编号。

    检查当前玩家是否可以取kk个石子1kMi(1 ≤ k ≤ Mi),使得dp[sk]dp[s - k] = 00

    如果存在这样的kk,则dp[s]dp[s] = 11;否则dp[s]dp[s] = 00

    输出结果:

    初始石子数为SS时,dp[S]dp[S]的值即为答案。

    C++代码实现:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
     
    int dp[25][(1<<14)+10];
    int n,S,a[25];
     
    int dfs(int x,int sum){
    	if(sum==0) return dp[x][sum]=1;
    	if(dp[x][sum]!=-1) return dp[x][sum];
    	for(int i=1;i<=a[x]&&i<=sum;i++){
            //能达到必败态的是必胜态
    		if(!dfs((x+1)%n,sum-i)) return dp[x][sum]=1;
    	}
        //只能达到必胜态的是必败态
    	return dp[x][sum]=0;
    }
     
    int main()
    {
        while(scanf("%d",&n)&&n){
        	scanf("%d",&S); 
        	n<<=1;
        	for(int i=0;i<n;i++){
        		scanf("%d",&a[i]);
    		}
    		memset(dp,-1,sizeof(dp));
    	    printf("%d\n",dfs(0,S));
    	}
    }
    • 1

    信息

    ID
    1069
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者