首页 > 其他 > 详细

nim博弈题

时间:2020-12-26 11:40:10      阅读:24      评论:0      收藏:0      [点我收藏+]

取(m堆)石子游戏 HDU - 2176 vj

题意概述:给出n堆石子,nim博弈判谁能赢,并且如果先手获胜输出所有先手获胜的第一步方案。

复习了一下\(nim\)博弈.
判赢的\(nim\)异或和\(nim = a_{1} \oplus a_{2} \oplus a_{3} \oplus a_{4}\oplus \cdots \oplus a_{n}\)

如果\(nim\)和为\(0\)先手必败
否则,我们看这样一组数

0001
0010
0100
1000
\(nim\)和为1111显然,所以先手必赢,那么先手如何赢?就是通过一个操作,让下一步该对面先手时,处于必败态。什么操作?就是让下一步对面面临着nim和为0,

首先要知道\(a \oplus b \oplus a = b\)所以可让\(t = nim \oplus a_{i}\)这样再判\(t\)是否小于\(a_{i}\),如果小于,那麽\(t\)一定可以从\(a_{i}\)取出来,如果不能,说明这堆不能操作,得找其他堆进行操作

我还想胡乱证明一下为什么nim和大于0,一定能找到一种方式,使得该对方先手时,nim积为0。
因为\(nim\)一定存在一个最高位,这是必然的,那么造成\(nim\)的这个最高位\(a\),他一定是也有这个最高位的,如果\(t = nim \oplus a_{i}\)那么\(t\)一定小于\(a\),也就是一定存在方案。

#include <iostream>

using namespace std;
int cas = 0;
int m;
int a[200099];
void solve() {
    for (int i = 1; i <= m; i++) 
        cin >> a[i];
    int nim = 0;
    for (int i = 1; i <= m; i++) 
        nim ^= a[i];
    if (nim == 0) {
        cout << "No\n";
    } else {
        cout << "Yes\n";
        for (int i = 1; i <= m; i++) {
            int Nim = nim^a[i];
            if (Nim < a[i]) {
                cout << a[i] << " " << Nim << endl;
            }
        }
    }
}
int main()
{
    while (cin >> m) {
        if (m == 0)return 0;
        solve();
    }
}

nim博弈题

原文:https://www.cnblogs.com/Xiao-yan/p/14191621.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!