Nim-硬币游戏2(Java)

n堆硬币,每堆各有xi枚硬币。给定k个数字 a1,a2,a3,…,ak。两人轮流选出一堆硬币,从中取出一些硬币。每次所取硬币枚数一定要在a1,a2,a3,…,ak中。

模板题,贴上java代码

public class Main {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt();
        int k = reader.nextInt();
        int[] a = new int[k];
        int[] x = new int[n];
        for (int i = 0; i < k; i++) {
            a[i] = reader.nextInt();
        }
        for (int i = 0; i < n; i++) {
            x[i] = reader.nextInt();
        }
        int max_x = Arrays.stream(x).max().getAsInt();
        int[] sg = new int[max_x + 1];
        for (int i = 1; i <= max_x; i++) {
            Set<Integer> set = new HashSet<>();
            for (int j = 0; j < k; j++) {
                if (a[j] <= i) {
                    set.add(sg[i - a[j]]);// 枚举所有可以进行的操作
                }
            }
            int g = 0;
            while (set.contains(g)) {
                g++;// mex操作,最小非负
            }
            sg[i] = g;
            //System.out.println(g);
        }
        int ans = 0;
        for (int i = 0; i < n; i++) {
            ans ^= sg[x[i]];
        }
        if (ans == 0) {
            System.out.println("Bob");
        } else {
            System.out.println("Alice");
        }
    }
}

啊好开心,在知乎有关sg函数的回答被大v翻牌了,收获了俩超强大佬的关注,爽飞。但是总感觉自己的理解还是有不对的地方,这里也贴上了留待以后修改吧。

**异或运算是二进制数的运算,若参与异或运算的两个数相同的二进制位的值不同,则该位运算结果为1,否则为0。对于nim游戏进行一整套的异或运算,其实是在判断游戏在开始时是否处于一个所谓的“平衡”局面。若平衡(全部异或下来的值为0),则对于经典的nim游戏胜败判定(无法行动的人负),先手必败,反之,不平衡(大于0)则先手必胜。
“平衡”局面的判定是二进制层面的,这里具体化的来说,就是把nim游戏中的每一堆硬币(或者木块石子什么的)按堆一字排开,再按照二进制的规则摆放,即从右到左按照1,2,4,8….这样的规则放置,比如一堆3个,就从右到左能摆成1,2这样的局面,5则能摆成1,空,4这样。说起来比较晦涩,可以自己摆摆看。对于每一位,如果所有堆这样排开之后,这一位(列)上非空的个数是偶数,则说这一位(列)是平衡的,如果所有位都是平衡的,则说这个nim游戏局面是平衡的。
嗯,这就完成了第一步,把具体的nim游戏转成二进制运算,把堆内的硬币数转成二进制后1就相当于这一位是有所摆放的(不是很会描述这个,5个硬币从右到左摆出来是1,空,4,而5的二进制是101。3摆出来是1,2,而3的二进制是11,言辞浅薄甚是抱歉,请诸位意会)。一次异或运算就是在计算每两堆的局面是否平衡,n次异或运算就是在计算整个局面是否平衡,平衡的局面算出来绝对是0。
至于“平衡”状态与胜败的关系,则是面临平衡局面的人任何操作都会打破平衡,面对不平衡局面的人所能采取的最优操作就是维持平衡,维持到最后,就能主动营造必胜局面。
扩展到sg函数,sg函数是一种把一个大游戏拆成n个符合nim规则的小游戏,连续sg异或就是判断整个大游戏的局面是否平衡,从而得出胜败。**

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值