zoukankan      html  css  js  c++  java
  • 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) 其实是假题? 不懂..

  • 相关阅读:
    MySql 语言分类
    grep正则 以.o结尾的文件
    demo板 apt-get install stress
    ltp-ddt qspi_mtd_dd_rw error can't read superblock on /dev/mtdblock0
    linux 系统中的 /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin 目录的区别
    setenv和dos2unix碰到的问题
    bootz to be continued
    runltp出现问题 [
    demo board boot mode
    excel条件格式 满足包含xx的整行高亮
  • 原文地址:https://www.cnblogs.com/linqi05/p/13764409.html
Copyright © 2011-2022 走看看