• Nim K博弈与SG值存疑(POJ 2315)


    题意

    问题转化成, 有 (N) 堆石子, 博弈双方每次可以选择不超过 (K) 堆, 每堆取不超过 (X) 个, 总的取石子数至少为 (1). 最后没有石子可取的一方判负. 问胜利方.

    网上的题解

    对于单堆来说是一个巴什博弈, (SG) 值为石子数模 (X+1).

    (Nim K) 博弈是在 (Nim) 博弈的基础上, 把每次选择一堆石子扩展成 (1-K) 堆. 其做法是, 把所有石子数转成二进制, 每一位做模 (K+1) 的加法, 若最后结果不为 (0) 先手胜, 否则后手胜.

    相关的证明

    POJ2315 AC 代码
    #define inc(i, l, r) for (int i = l; i <= r; i++)
    
    const double PI = acos(-1.0); 
    
    int N, M, L, R; 
    int sg[35], num[35]; 
    
    int main() {
    
        while (scanf("%d %d %d %d", &N, &M, &L, &R) != EOF) {
            inc(i, 0, 31) num[i] = 0;
            int mx = L / (2 * PI * R);
            int x;
            inc(i, 1, N) {
                scanf("%d", &x);
                sg[i] = (int)((ceil)(x / (2 * PI * R))) % (mx + 1);
                int top = 0;
                while (sg[i]) {
                    num[top++] += sg[i] & 1;
                    sg[i] >>= 1;
                }
            }
            int fail = 1;
            inc(i, 0, 31) if (num[i] % (M + 1)) fail = 0;
            if (fail)
                printf("Bob
    ");
            else
                printf("Alice
    ");
        }
    
    }
    

    看起来好像没啥问题? 但是, 我在打表的结果里发现了不止一个对不上结论的数据.

    打表程序
    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define inc(i, l, r) for (int i = l; i <= r; i++)
    
    const int MAXN = 6;  //打表石子数的上限
    
    const int N = 4;  //石子堆数
    const int M = 2;  //最多取多少堆
    const int X = 2;  //每堆至多取
    
    #define ar array<int, N>
    
    map<ar, int> mp;
    ar target, now;
    
    int dfs(int top) {
        if (top == N) {
            int tot = 0;
            inc(i, 0, N - 1) tot += int(now[i] > 0);
            if (tot > 0 && tot <= M) {
                ar res;
                inc(i, 0, N - 1) res[i] = target[i] - now[i];
                return mp[res];
            }
            return 1;
        }
        inc(i, 0, min(X, target[top])) {
            now[top] = i;
            if (!dfs(top + 1)) {
                return 0;
            }
        }
        return 1;
    }
    int num[35];
    ar b;
    void solve(int top) {
        if (top == N) {
            target = b;
            mp[b] = !dfs(0);
            /*  if (!mp[b]) {
                 inc(i, 0, N - 1) cout << b[i] << " ";
                 cout << "
    ";
             }
             */
            int succ = 0;
            inc(i, 0, 31) num[i] = 0;
            inc(i, 0, N - 1) {
                int t = b[i] % (X + 1), tt = 0;
                while (t) {
                    num[tt] += t & 1;
                    t >>= 1;
                    tt++;
                }
            }
            inc(i, 0, 31) if (num[i] % (M + 1)) succ = 1;
            if (mp[b] != succ) {
                cout << "mp[b] is " << mp[b] << " succ is " << succ << "
    ";
                inc(i, 0, N - 1) cout << b[i] << " ";
                cout << "
    ";
            }
            return;
        }
        inc(i, 0, MAXN) {
            b[top] = i;
            solve(top + 1);
        }
    }
    
    int main() {
        // freopen("poj2315.out", "w", stdout);
        freopen("poj2315_false.out", "w", stdout);
        solve(0);
    }
    
    部分打表结果
    mp[b] is 1 succ is 0
    1 1 1 3 
    mp[b] is 1 succ is 0
    1 1 1 6 
    mp[b] is 1 succ is 0
    1 1 3 1 
    mp[b] is 1 succ is 0
    1 1 3 4 
    mp[b] is 0 succ is 1
    1 1 3 5 
    ...
    

    (N=4,K=2,X=2), 石子数分别为 (1,1,1,3), 按照理论做法, 取 (SG) 值为 (1,1,1,0), 二进制下每一位做模 (K+1) 的做法, 结果为 (0), 先手必败. 但事实上先手走 (0,1,1,1), 这是一个很显然的必败态, 即 (1,1,1,3) 实际上是必胜的.

    那么问题是出在哪了? 个人认为是 (SG) 值不能和 (Nim K) 博弈套在一起. 因为按照证明的流程, 每次都有 (K) 个数可以改变, 但实际上, 如果对手取的石子使 (SG) 值增大, 我方就必须把增大的 (SG) 值取回去, 也就是说并不一定还有 (K) 个数可以给我改变. 原本 (Nim) 博弈可以用 (SG) 值, 是因为对手使 (SG) 值增大时, 我方再取回去, 相当于没有变化, 所以只考虑 (SG) 值变小的情况.

    所以说 (POJ2315) 其实是假题? 不懂..

  • 相关阅读:
    我的有道难题算法-双倍超立方数
    终于获取了SharePoint.OpenDocument对象打开的Word对象
    Eclipse下的项目管理插件介绍
    初识 sqlite 与 content provider 学习笔记
    android 官方文档中的一些错误收集
    android TraceView (图形化性能测试工具)使用入门笔记
    Texttospeech 入门与进阶学习笔记(android)
    Intent进阶 和 Intentfilter 学习笔记
    android UI设计属性中英对照表(未修订)
    android学习笔记7天打造一个简易网络Mp3播放器
  • 原文地址:https://www.cnblogs.com/linqi05/p/13764409.html
Copyright © 2020-2023  润新知