0
点赞
收藏
分享

微信扫一扫

[带自己学/复习算法] 4.博弈论之SG函数

yundejia 2022-04-21 阅读 36
算法

先手必胜态 ( N : n o w w i n ) (N:now win) (N:nowwin)和先手必败态 ( P : p r e v i o u s w i n ) (P:previous win) (P:previouswin)是博弈论中很重要的概念。

我们可以通过状态间的转移来进行推理当前状态究竟是 N N N还是 P P P,以一个简单的Bash博弈例子为例:

有一堆石子数量为 n n n,每次可以取 1 − m 1-m 1m个石子,双方轮流取,直到不能取者输,那么问你是否当前先手必胜?

这个问题的经典做法是从最终结果反推,我们记 ( n u m b e r , s t a t u s ) (number, status) (number,status)为当前有 n u m b e r number number个石子,先手处于 N / P N/P N/P状态。我们从状态 ( 0 , P ) (0, P) (0,P)开始反推,可以知道 ( 1 ) (1) (1) ( m ) (m) (m)一定是状态N,即 ( 1 , N ) , . . . , ( m , N ) (1, N),..., (m, N) (1,N),...,(m,N),而 ( m + 1 ) (m+1) (m+1)一定是状态 P P P,因为在该状态下,无论怎么取,下一步到达的一定是状态 N N N,即另一方先手必赢。

于是参考这个思路,我们可以看出当前数量为 n n n时,我们只需要查看( n − 1 n-1 n1),( n − 2 n-2 n2),…,( n − m n-m nm)的状态是否都是状态先手必赢( N N N)即可,若全是则当前一定为必输状态 P P P;否则,则说明一定存在一个下一步状态为必输( P P P),那么我们只需要选择这种转移方式,即可让对面面临一个先手必输( P P P)的局势。

S G SG SG函数的定义,就是 S G ( x ) = S G ( S G ( y 1 ) , S G ( y 2 ) , . . . , S G ( y k ) ) SG(x) = SG(SG(y_1), SG(y_2),...,SG(y_k)) SG(x)=SG(SG(y1),SG(y2),...,SG(yk)),其中 y i y_i yi代表 x x x做一步操作后能转移到的状态。

S G SG SG函数的特点时, S G ( x ) = 0 SG(x)=0 SG(x)=0时先手必败。

class Game{

private:
    vector<int>cando;//cando数组为当前能做的所有操作,即每次可以取cando[i]个
    vector<int>SG;
    int n_;
public:
    Game(vector<int>cando_, int n){
        cando = cando_;
        SG = vector<int>(n, -1);
    }
    int getSG(int x){ // 记忆化搜索SG的值
        if(SG[x] != -1)return SG[x];
        vector<bool>vis(n_ + 1, false);
        for(int i = 0; i < vis.size();i++)vis[i] = false;
        for(int v : cando){
            if(x - v >=0)vis[getSG(x - v)] = true;
        }
        for(int i = 0; ; i++){
            if(!vis[i])return SG[x] = i;
        }
    }
    bool nowwin(int x){
        return getSG(x) != 0; // SG值为0则先手必败,否则先手必胜
    }
};
举报

相关推荐

0 条评论