zoukankan      html  css  js  c++  java
  • 博弈论--sg函数

    博弈论

    mex

    首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。

    例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。

    sg函数

    定义P-position和N-position,其中P代表Previous,N代表Next。

    直观的说,先手必败的局面是P-position,先手必胜的局面是N-position,

    定义sg(x)=mex{ sg(y) | y是x的子状态 },也就是说y可以由x转移过去。

    若x的所有子状态y都是必胜态,那么x就是必败态。

    若x的所有子状态y有一个必败态,那么x就是必胜态。

    如何求sg函数

    打表

    #include <bits/stdc++.h>
    using namespace std;
    #define mem(a,b) memset(a,b,sizeof(a))
    #define pii pair<int,int>
    #define int long long
    const int inf = 0x3f3f3f3f;
    const int maxn = 1110;
    const int M = 1e9+7;
    int n;
    
    int a[maxn];            //每次移动可以选取的值
    int sg[maxn];
    bool vis[maxn];
    
    void getsg()
    {
        for(int i = 1; i <= n; i++) 
        {
            mem(vis,0);
            for(int j = 1; a[j] <= i; j++)         //可以取的值
            {
                vis[sg[i-a[j]]] = 1;            //(i-a[j])状态可达
            }
            int res = 0;
            for(;;res++)
            {
                if(!vis[res]) break;
            }
            sg[i] = res;
        }
    }
    
    
    
    signed main()
    {
        cin>>n;
        sg[0] = 0;      //0表示必败
        for(int i = 1; i <= n; i++) 
        {
            a[i] = i*i;
        }
        getsg();
        for(int i = 1; i <= n; i++) 
        {
            cout<<sg[i]<<' ';
        }
        cout<<endl;
        return 0;
    }
    

    dfs

    int a[maxn];        //可以取的值
    
    int sg[maxn];
    
    int dfs_sg(int x)
    {
        if(sg[x] != -1) return sg[x];
        int i;                  //必须要声明一下
        bool vis[maxn];         //每次dfs对应不同的vis
        mem(vis,0);
        for(int i = 1; i <= n; i++) 
        {
            if(x - a[i] >= 0)
            {
                vis[dfs_sg(x-a[i])] = 1;
            }
        }
        int res = 0;
        for(;;res++)
        {
            if(!vis[res]) break;
        }
        return sg[x] = res;
    }
    

    简化版本的sg

    bool winnerSquareGame(int n) {
        vector<int> v;
        for(int i = 1; i*i <= n; i++) 
        {
            v.push_back(i*i);
        }
        vector<int> sg(n+1);                  //只有两种值,0或1,0代表必败
        for(int i = 1; i <= n; i++) 
        {
            for(auto j : v)
            {
                if(j <= i)
                {
                    if(!sg[i-j])                  //如果子状态有必败,那么我必胜
                    {
                        sg[i] = 1;
                        break;
                    }
                }
                else break;
            }
        }
        return sg[n];
    }
    
  • 相关阅读:
    挑战安全的捉迷藏病毒和木马的隐藏手段
    如何清除局域网中的ARP病毒
    挑战安全的捉迷藏病毒和木马的隐藏手段
    MS07027:Internet Explorer本月累积性安全更新
    对Autorun.inf类U盘病毒的攻防经验总结
    对Autorun.inf类U盘病毒的攻防经验总结
    如何清除局域网中的ARP病毒
    挂马方式和系统判断等代码
    linux下phpMyAdmin泛起1045 Access denied for 的措置
    在ubuntu8.04上用evolution接受163邮件
  • 原文地址:https://www.cnblogs.com/hezongdnf/p/12867343.html
Copyright © 2011-2022 走看看