LeetCode/Nim游戏

你和你的朋友,两个人一起玩 Nim 游戏:

桌子上有一堆石头。
你们轮流进行自己的回合,你作为先手 。
每一回合,轮到的人拿掉 1-3块石头。
拿掉最后一块石头的人就是获胜者。
假设你们每一步都是最优解。请编写一个函数,来判断你是否可以在给定石头数量为 n 的情况下赢得游戏。如果可以赢,返回 true,否则,返回 false 。

1. 博弈

首先考虑到1、2、3是必赢的边界条件
对于其余值,看自己是否必赢,得看对面是否必输
对于评估函数canWinNim(),判断n是否必赢,可以将问题转移
即可以分别选择1、2、3块石头,变成对n-1、n-2、n-3的必输评判
我必然会选择最优解,所以只要n-1、n-2、n-3中有一个为false,表示对面输,所以自己赢
所以会得到canWinNim(n)=!(canWinNim(n-1)&canWinNim(n-2)&canWinNim(n-3))

递归博弈
class Solution {
public:
    bool canWinNim(int n) {
       if(n<4) return true;
       return !(canWinNim(n-1)&canWinNim(n-2)&canWinNim(n-3));
    }
};
正向优化
class Solution {
public:
    bool canWinNim(int n) {
        vector<bool> dp(n+1,1);
        for(int i=4;i<n+1;i++)
            dp[i]=!(dp[i-1]&dp[i-2]&dp[i-3]);
       return dp[n];
    }
};

2. 数学规律

可以观察归纳得到规律,4的倍数为输

class Solution {
public:
    bool canWinNim(int n) {//123赢 4输 567赢
      if(n%4==0) return false;
        else return true;
    }
};
更简洁
class Solution {
public:
    bool canWinNim(int n) {
        return n & 3;
    }
};
posted @ 2022-05-17 00:51  失控D大白兔  阅读(51)  评论(0编辑  收藏  举报