zoukankan      html  css  js  c++  java
  • nim博弈题

    取(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
    ";
        } else {
            cout << "Yes
    ";
            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();
        }
    }
    
    
  • 相关阅读:
    最近学习的情况
    0Day – 2011.1.12[From B4A]考试终于完了
    PHP 在NetBeans中的测试[转自NetBeans.org]
    12月武汉下雪了
    Delphi下指针使用总结
    0Day – 2010.12.27[转自B4A]
    AQTime教程
    C #define理解
    C 环境的搭配
    数据结构 字符串的模式匹配
  • 原文地址:https://www.cnblogs.com/Xiao-yan/p/14191621.html
Copyright © 2011-2022 走看看