[LeetCode] 【博弈论】Nim游戏

314 阅读2分钟

这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战

题目

leetcode-cn.com/problems/ni…

PS:在不知道学什么的时候,只能刷刷题了,Spring和JVM看着着实累人

解析

博弈论的问题一概都很恶心,之前也有过类似的题解(比如说之前的各种石子游戏)。不过既然刷到了,就看看怎么做吧,万一面试问到了呢。

分析一下:拿到最后一个石子的,赢了。

那么这就代表着:

  • 如果在最后一次我取的时候,只能取到这堆东西剩1~3个,那么我是必输的。
  • 反过来,如果最后一次对手取的时候,只能取到这堆东西剩1~3个,那么我必赢。

这个条件就代表着:如果A必赢,那么A倒数第二次取之后,就会恰好剩4个,这样无论对手最后一次怎么取,自己都可以取到最后一个;这个恰好剩4个,就可以转化为取得倒数第5个的人必然会获胜。

那么就得到了第一个看起来像样的推导答案:

取得最后一个的人会获胜->取得倒数第五个的人会获胜。

同理可以推得:取得倒数第9个的人必定获胜。

因此得出一个公式:

取得倒数第4i+1个石子的人,必然获胜,i>=1。

另外:在石子数量小于5的时候,需要分别区分一下:仅当石子数=4的时候,是不可能赢的。

那么,如果要解答这个问题,就需要看看:如何将上述的公式倒推到第一次怎么取。

其实只需要看看,对于最大可允许的i第一次是否能够取到?取得到,那么我必胜;取不到,那么我必输。

就是这么说:如果最大的i为1,那么就是存在倒数第5个;此时,需要看看:是否能够在第一次取到倒数第5个数。倒数第5个数,如果此时有8个数,倒数第5个数就代表着是正数第4个数

代码其实就很简单了:

public boolean canWinNim(int n) {
    int w = (n-1)/4;
    if(n-(w*4+1)>=3) return false;
    return true;
    //换言之,其实就是下面这个:return (n-1)%4!=3;
}

执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户

内存消耗:38.2 MB, 在所有 Java 提交中击败了5.26%的用户