硬币收集2人游戏

Posted

技术标签:

【中文标题】硬币收集2人游戏【英文标题】:Coin collection 2 player game 【发布时间】:2021-12-28 05:44:23 【问题描述】:

考虑一个包含 n 个正整数值的硬币和两个玩家 player1 和 player2 的数组。每个玩家轮流拿硬币,直到剩下硬币。那个有 最大值获胜。玩家可以拿走的硬币数量由变量 S 初始 =1 控制,玩家可以从左边连续拿走 k 个硬币,其中 1我们必须找到最大数量 玩家1可以在游戏中获得的硬币价值 例如:如果输入是 [3,6,8,5,4],输出应该是 12,因为如果玩家 1 拿了一个硬币,玩家 2 拿了 2 个硬币,然后玩家 1 重新拿了 2 个硬币。所以player1 将有 3 + 5 + 4 = 12。 我的想法:我觉得可以使用动态编程来实现它,但我找不到子问题或最优子结构。条件看起来非常复杂。关于如何解决这个问题的任何想法?

【问题讨论】:

如果找不到子问题,是什么让您认为动态规划是一种可能/好的方法? 子问题由剩余的硬币和 S 的值定义。例如,如果 player1 拿了一枚硬币,则子问题是 [6,8,5,4]S=1。但是如果 player1 拿了两个硬币,子问题是 [8,5,4]S=2 【参考方案1】:

子问题通过以下方式识别:

已拿走的硬币数量。否则输入:coins 数组中的索引,可以从中取出下一个硬币。 S的值。

由于可以取出的硬币数量和S的值永远不会超过硬币数量?,我们可以使用大小为?的矩阵来记忆结果。

轮到记忆并不重要:无论轮到谁,他们在相同的状态下都有相同的机会。因此,如果我们遇到玩家 1 的状态并评估它(最大化硬币价值),然后遇到相同的状态,但玩家 2 可以玩,那么之前的结果可以应用于玩家 2。

算法可以使用递归。基本情况发生在当前玩家可以决定拿走所有剩余的硬币时。当然,这永远是最好的选择。

对于递归情况,可以播放当前玩家的所有可能动作。对于每一个对手的最佳得分都可以通过递归调用得出。当前玩家的最佳走法是让对手的最佳得分最小化

这是 javascript 中的一个实现。运行这个 sn-p 将解决您在问题中提出的问题,以及 [1,1,1,1,1,1,1]:

function solve(coins) 
    let n = coins.length;
    // Preprocessing: for all possibly suffix arrays, calculate the sum of the coins
    let sums = coins.slice(); // copy 
    for (let i = n - 2; i >= 0; i--) 
        sums[i] += sums[i + 1]; // backwards running sum
    

    // 2D Array for memoization (dynamic programming)
    let dp = []; // n x n matrix, initially filled with -1
    for (let i = 0; i < n; i++) dp.push(Array(n).fill(-1));

    return recur(0, 1);
    
    function recur(start, s) 
        if (n - start <= 2*s) return sums[start]; // base case: take all remaining coins
        if (dp[start][s] == -1)  // sub problem was not encountered before
            let minOpponentScore = Infinity;
            // For each possible move, get best counter move from opponent
            for (let k = 1; k <= 2*s; k++) 
                // We'll take the move where the best counter move was the worst
                minOpponentScore = Math.min(minOpponentScore, recur(start + k, Math.max(k, s)));
            
            dp[start][s] = sums[start] - minOpponentScore;
        
        return dp[start][s];
    


console.log(solve([3,6,8,5,4]));
console.log(solve([1,1,1,1,1,1,1]));

【讨论】:

那是天才的一击。非常感谢。只是想知道一些关于你的事情。你做什么工作?您从事软件开发吗? 我在 91 年代开始担任专业软件开发人员,从 80 年代中期开始迷上它。演变为 IT 项目经理。 酷。你最喜欢的软件书籍是什么?您认为必须阅读以深入了解事物的内容。我是一名 Java 开发人员,但很想深入研究。 我真的不能推荐一本书。我上一次阅读有关软件开发的文章已经很多年了。

以上是关于硬币收集2人游戏的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的声音让我的游戏在 Swift Spritekit 中滞后?

好题收集 游戏(数学+思维)

NOI 4976:硬币

PlayerPrefs.SetInt 和 .GetInt 具有不良影响

OpenJudge NOI 4976 硬币

Bailian4120 硬币0-1背包