【c++/java】Nim游戏(博弈论证明)

891.Nim游戏

给定 n 堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。

问如果两人都采用最优策略,先手是否必胜。

输入格式
第一行包含整数 n。

第二行包含 n 个数字,其中第 i 个数字表示第 i 堆石子的数量。

输出格式
如果先手方必胜,则输出 Yes。

否则,输出 No。

数据范围
1≤n≤105,
1≤每堆石子数≤109
输入样例:
2
2 3
输出样例:
Yes
本题思路
公平组合游戏:
若一个游戏满足:

  • 由两名玩家交替行动
  • 在游戏进行的任意时刻,可以执行合法行动与轮到哪位玩家无关
  • 不能行动的玩家判负

eg:围棋不是公平组合游戏
解释必胜状态和必败状态:
必胜状态:先手进行某一特定操作,留给后手的只有失败,对于先手来说是必胜状态
必败状态:先手无论如何操作,留给后手的只有必胜状态,对于先手来说是必败状态
操作步骤
分别有两堆:2,3

  • 先手从第二堆拿走一个,此时第二堆与第一堆数目相同
  • 无论后手怎么拿,先手对后手镜像操作,即后手与先手操作相同

本题结论
假设n堆石子,分别为a1,a2,a3,……,an,如果a1⊕ a2⊕ a3⊕,……,⊕ an≠0,先手必胜,否则先手必败.
最终结果0⊕0⊕0⊕0,……,⊕0=0
结论证明
在操作过程中,如果a1⊕ a2⊕ a3⊕,……,⊕ an=x≠0,那么玩家一定会通过拿走某一堆中的石子导致结果变为零。

  • 证明:假设x的二进制最高不为0位在第k位,在a1,a2,……an种必有一个ai,ai的第k位为1,使得ai⊕x 【c++/java】Nim游戏(博弈论证明)_第1张图片
    那么从第i堆拿走(ai-ai⊕x)个石子后,第i堆还剩ai-(ai-ai⊕x)=ai⊕x;
    a1⊕ a2⊕ a3⊕,……,⊕ an=x⊕x=0

如果a1⊕ a2⊕ a3⊕,……,⊕ an=0,无论怎么先手,都会使得a1⊕ a2⊕ a3⊕,……,⊕ an≠0。

  • 证明:假设从第i堆拿走一些石子,原有ai个石子,现有ai’个石子,反证法:如果a1⊕ a2⊕ ai’⊕,……,⊕ an=0,则
    (a1⊕ a2⊕ a3⊕,……,⊕ an)⊕(a1⊕ a2⊕ ai⊕,……,⊕ an)=ai⊕ai’=0,即ai=ai’,矛盾,所以a1⊕ a2⊕ a3⊕,……,⊕ an=0,无论怎么先手,都会使a1⊕ a2⊕ a3⊕,……,⊕ an≠0。
    c++
#include 
using namespace std;
int main()
{
     
    int n;
    cin>>n;
    int res=0;
    for(int i=0;i<n;i++)
    {
     
        int x;
        cin>>x;
        res^=x;
    }
    if(res==0)puts("No");
    else puts("Yes");
    return 0;
}

java

import java.util.Scanner;
public class Main {
     
    public static void main(String[] args) {
     
        Scanner scanner=new Scanner(System.in);
        int n=scanner.nextInt();
        int res=1;
        for(int i=0;i<n;i++)
        {
     
            int a=scanner.nextInt();
            res^=a;
        }
        System.out.println((res^1)!=0?"Yes":"No");
    }
}

你可能感兴趣的:(ACWing基础算法,C++,java,c++,java,博弈论)