2021牛客多校#1 Alice and Bob(博弈论)

题目链接

          https://ac.nowcoder.com/acm/contest/11166/A

题目大意

有两堆石头,数量分别为 n,m 。两个人轮流操作,每次可以从一堆石头中拿走 k ( k > 0 ) k(k>0) k(k>0)块石头,在另一堆中拿走 s ∗ k ( s ≥ 0 ) s*k(s≥0) sks0个石头。
不能操作者输。双方均采取最优策略,求先手胜还是后手胜。

题解

由于Alice和Bob都是 电脑 聪明人所以他们每一步都是最优解,即若当前角色有必胜的策略,那么另一个角色就是必败的。
设必败态为 ( x , y ) (x,y) (x,y)
那么必胜态为 ( x + i , y + i ∗ j ) , ( x + i ∗ j , y + i ) (x+i,y+i*j),(x+i*j,y+i) (x+i,y+ij),(x+ij,y+i)
i为正整数,j为非负整数
由题意可得的必败态有 ( 0 , 0 ) (0,0) (0,0)
故可以继续推下去

参考代码

#include<bits/stdc++.h>
using namespace std;
const int N=5050;
int dp[N][N];
int main()
{
    dp[0][0]=0;
    for(int x=0;x<N;x++)
    for(int y=0;y<=x;y++)
    {
        if(dp[x][y]==0)
        {
            for(int i=1;i+x<N;i++)
                for(int j=0;i*j+y<N;j++)
                {
                    int xx=i+x,yy=i*j+y;
                    if(xx<yy)swap(xx,yy);
                    dp[xx][yy]=1;
                }
            for(int i=1;i+y<N;i++)
                for(int j=0;i*j+x<N;j++)
                {
                    int xx=i*j+x,yy=i+y;
                    if(xx<yy)swap(xx,yy);
                    dp[xx][yy]=1;
                }
        }
    }
    int T,n,m;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        if(n<m)swap(n,m);
        if(dp[n][m])printf("Alice\n");
        else printf("Bob\n");
    }
}

总结

通过预处理dp数组,进来一个输出一个即可。
水题(划去)

### 联合活动 Chocolate 问题解题思路 #### 背景描述 在网的联合活动中,“Chocolate”问题是关于如何合理分配巧克力给朋友。具体来说,目标是通过K次切割将一块由个连续部分组成的巧克力分成K+1份,每一份都包含一些连续的部分。 #### 解决方案概述 为了有效地解决这个问题,可以采用动态规划的方法来寻找最优解法。该方法的核心在于定义状态转移方程以及初始化边界条件[^1]。 #### 动态规划实现细节 - **状态表示**:设`dp[i][j]`代表前i个块中做最j刀所能获得的最大价值。 - **初始条件**:当没有切分时(`j=0`),最大值即为整个区间的总和;对于其他情况,则需遍历所有可能的位置进行尝试。 - **状态转移**:对于每一个新的位置k,在其之前已经完成了一定数量的分割操作(j),此时需要计算从当前位置到起点之间的最小成本,并更新全局最优解。 ```python def max_chocolate_value(chunks, K): n = len(chunks) # 计算区间内的累积和用于快速求子数组之和 prefix_sum = [0] * (n + 1) for i in range(1, n + 1): prefix_sum[i] = prefix_sum[i - 1] + chunks[i - 1] dp = [[float(&#39;-inf&#39;)] * (K + 1) for _ in range(n)] # 初始化第一列 for i in range(n): dp[i][0] = prefix_sum[i + 1] for j in range(K + 1): # 遍历每一刀数目的可能性 for i in range(n): # 当前考虑到第几个chunk为止 if j == 0 or i < j: continue for p in range(i): # 尝试不同的最后一刀位置p cost = abs(prefix_sum[p + 1] - prefix_sum[i + 1]) dp[i][j] = max(dp[i][j], min(dp[p][j - 1], cost)) return dp[-1][-1] ``` 此算法的时间复杂度主要取决于三重循环结构O(N^3*K),其中N为chunks的数量,K为允许的最大切割次数。虽然看起来效率不高但对于题目规模而言是可以接受的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值