hdu3032(sg博弈)

作者: sugar_coated | 来源:发表于2016-10-02 22:31 被阅读70次

    对于hdu3032题描述如下:


    Paste_Image.png

    Sample Input

    2
    3
    2 2 3
    2
    3 3

    Sample Output

    Alice
    Bob

    如果不可以分成两堆,就是一个Nim的经典游戏。对于Nim游戏,有以下结论:

    a1 xor a2 xor ...xor an != 0 必胜态
    a1 xor a2 xor ...xor an == 0 必败态

    首先,一旦从xor为零的状态取走至少一颗石子,xor就一定会变成非零,所以必败态只能转移到必胜态。
    然后,观察xor的二进制表示最高位的1,选取石子数的二进制表示对应位也为1的某堆石子。只要从中取走使得该位变为零,且其余xor中的1也反转的数量的石子,xor就可以变为零。因此,必胜态总是可以转移到某个必败态。
    所以,计算异或值就可以得到结果,非零则Alice必胜,为零则Bob必胜。

    int n;//有n堆object
    int arr[MAX_N];//每堆的个数
    
    void solve() {
        int x = 0;//因为0与任何数异或都为此数本身
        for (int i = 0; i < n; ++i)
            x ^= arr[i];
        if (x != 0) puts("Alice");
        else puts("Bob");
    }
    

    利用Nim的思想对sg函数打表,可以找到此题的规律。先贴上打表代码:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    const int MAX_N = 100;
    int sg[MAX_N];//sg函数
    bool vis[MAX_N];//标记数组
    
    void solve(int n) {
        memset(vis, false, sizeof(vis));
        for (int i = 0; i < n; ++i)
            vis[sg[i]] = true;
        for (int i = 1; i <= n; ++i)//因为可以分成两堆,如果三堆,就写三重循环
            for (int j = 1; j <= n; ++j) {
                if (i + j == n) vis[sg[i] ^ sg[j]] = true;
            }
        int i;
        for (i = 0; ; ++i)//没有i < n,如果都不成立,最后i = n
            if (!vis[i]) break;
        sg[n] = i;
        cout << "sg[" << n << "]=" << i << endl;
    }
    
    int main() {
        memset(sg, 0, sizeof(sg));
        for (int i = 1; i < 50; ++i) {
            solve(i);
        }
        return 0;
    }
    
    

    运行结果为:

    Paste_Image.png

    由此可以得到题解:

    #include <iostream>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(NULL);
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            int ans = 0;
            while (n--) {
                int val;
                cin >> val;
                if (val % 4 == 3) ans ^= val + 1;
                else if (val % 4 == 0) ans ^= val - 1;
                else ans ^= val;
            }
            cout << (ans ? "Alice" : "Bob") << endl;
        }
        return 0;
    }
    

    相关文章

      网友评论

        本文标题:hdu3032(sg博弈)

        本文链接:https://www.haomeiwen.com/subject/mnxlyttx.html