• sg函数模板


    sg[i]为0表示i节点先手必败。

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

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

    对于一个给定的有向无环图,定义关于图的每个顶点的Sprague-Grundy函数g如下:g(x)=mex{ g(y) | y是x的后继 },这里的g(x)即sg[x]

    例如:取石子问题,有1堆n个的石子,每次只能取{1,3,4}个石子,先取完石子者胜利,那么各个数的SG值为多少?

    sg[0]=0,f[]={1,3,4},

    x=1时,可以取走1-f{1}个石子,剩余{0}个,mex{sg[0]}={0},故sg[1]=1;

    x=2时,可以取走2-f{1}个石子,剩余{1}个,mex{sg[1]}={1},故sg[2]=0;

    x=3时,可以取走3-f{1,3}个石子,剩余{2,0}个,mex{sg[2],sg[0]}={0,0},故sg[3]=1;

    x=4时,可以取走4-f{1,3,4}个石子,剩余{3,1,0}个,mex{sg[3],sg[1],sg[0]}={1,1,0},故sg[4]=2;

    x=5时,可以取走5-f{1,3,4}个石子,剩余{4,2,1}个,mex{sg[4],sg[2],sg[1]}={2,0,1},故sg[5]=3;

    以此类推.....

       x         0  1  2  3  4  5  6  7  8....

    sg[x]      0  1  0  1  2  3  2  0  1....

    计算从1-n范围内的sg值,

    s[]存储可以走的步数,s[0]表示可以有多少种走法

    s[]需要从小到大排序

    1.可选步数为1~m的连续整数,直接取模即可,sg[x] = x % (m+1);

    2.可选步数为任意步,sg[x] = x;

    3.可选步数为一系列不连续的数,用sg函数计算

    模板1(dfs):

     1 /*
     2 s数组表示合法移动集合,从小到大排序。sNum合法移动个数
     3 sg数组初始化为-1,对每个集合s仅需初始化1次
     4 */
     5 const int MAXN = 20;//s集合大小
     6 const int MAXM = 1000 + 5;//
     7 int s[MAXN], sNum;
     8 int sg[MAXM];
     9 
    10 int dfsSg(int x)
    11 {
    12     if (sg[x] != -1) {
    13         return sg[x];
    14     }
    15     int i;
    16     bool vis[MAXN];//sg值小于等于合法移动个数sNum
    17 
    18     memset(vis, false, sizeof(vis));
    19     for (i = 0; i < sNum && s[i] <= x; ++i) {
    20         dfsSg(x - s[i]);
    21         vis[sg[x - s[i]]] = true;
    22     }
    23     for (i = 0; i <= sNum; ++i) {
    24         if (!vis[i]) {
    25             sg[x] = i;
    26             break;
    27         }
    28     }
    29     return sg[x];
    30 }
    View Code

    模板2(打表):

    求出所有sg值,有时没必要,用dfs就行

     1 /*
     2 s数组表示合法移动集合,从小到大排序。sNum合法移动个数
     3 sg值对每个集合s仅需求一次
     4 */
     5 const int MAXN = 20;//s集合大小
     6 const int MAXM = 1000 + 5;//
     7 int s[MAXN], sNum;
     8 int sg[MAXM];
     9 bool exist[MAXN];//sg值小于等于合法移动个数sNum
    10 
    11 void getSg(int n)
    12 {
    13     int i, j;
    14     sg[0] = 0;//必败态
    15     for (i = 1; i <= n; ++i) {
    16         memset(exist, false, sizeof(exist));
    17         for (j = 0; j < sNum && s[j] <= i; ++j) {
    18             exist[sg[i - s[j]]] = true;
    19         }
    20         for (j = 0; j <= sNum; ++j) {
    21             if (!exist[j]) {
    22                 sg[i] = j;
    23                 break;
    24             }
    25         }
    26     }
    27 }
    View Code

    hdu 1848 Fibonacci again and again(sg)

    取石子问题,一共有3堆石子,每次只能取斐波那契数个石子,先取完石子者胜利,问先手胜还是后手胜

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 /*
     5 s数组表示合法移动集合,从小到大排序。sNum合法移动个数
     6 sg数组初始化为-1,对每个集合s仅需初始化1次
     7 */
     8 const int MAXN = 20;//s集合大小
     9 const int MAXM = 1000 + 5;//
    10 int s[MAXN], sNum;
    11 int sg[MAXM];
    12 
    13 int dfsSg(int x)
    14 {
    15     if (sg[x] != -1) {
    16         return sg[x];
    17     }
    18     int i;
    19     bool vis[MAXN];//sg值小于等于合法移动个数sNum
    20 
    21     memset(vis, false, sizeof(vis));
    22     for (i = 0; i < sNum && s[i] <= x; ++i) {
    23         dfsSg(x - s[i]);
    24         vis[sg[x - s[i]]] = true;
    25     }
    26     for (i = 0; i <= sNum; ++i) {
    27         if (!vis[i]) {
    28             sg[x] = i;
    29             break;
    30         }
    31     }
    32     return sg[x];
    33 }
    34 
    35 int main()
    36 {
    37     int i;
    38     s[0] = 1;
    39     s[1] = 2;
    40     for (i = 2; i < MAXN; ++i) {
    41         s[i] = s[i - 1] + s[i - 2];
    42         //printf("%d %d
    ", i, s[i]);
    43     }
    44     sNum = 16;
    45     int m, n, p;
    46     int sum;
    47     memset(sg, -1, sizeof(sg));
    48     while (~scanf("%d%d%d", &m, &n, &p)) {
    49         if (m == 0 && n == 0 && p == 0) {
    50             break;
    51         }
    52         dfsSg(m);
    53         dfsSg(n);
    54         dfsSg(p);
    55         sum = sg[m] ^ sg[n] ^ sg[p];
    56         if (sum != 0) {
    57             printf("Fibo
    ");
    58         } else {
    59             printf("Nacci
    ");
    60         }
    61     }
    62     return 0;
    63 }
    View Code
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 /*
     5 s数组表示合法移动集合,从小到大排序。sNum合法移动个数
     6 sg值对每个集合s仅需求一次
     7 */
     8 const int MAXN = 20;//s集合大小
     9 const int MAXM = 1000 + 5;//
    10 int s[MAXN], sNum;
    11 int sg[MAXM];
    12 bool exist[MAXN];//sg值小于等于合法移动个数sNum
    13 
    14 void getSg(int n)
    15 {
    16     int i, j;
    17     sg[0] = 0;//必败态
    18     for (i = 1; i <= n; ++i) {
    19         memset(exist, false, sizeof(exist));
    20         for (j = 0; j < sNum && s[j] <= i; ++j) {
    21             exist[sg[i - s[j]]] = true;
    22         }
    23         for (j = 0; j <= sNum; ++j) {
    24             if (!exist[j]) {
    25                 sg[i] = j;
    26                 break;
    27             }
    28         }
    29     }
    30 }
    31 
    32 int main()
    33 {
    34     int i;
    35     s[0] = 1;
    36     s[1] = 2;
    37     for (i = 2; i < MAXN; ++i) {
    38         s[i] = s[i - 1] + s[i - 2];
    39         //printf("%d %d
    ", i, s[i]);
    40     }
    41     sNum = 16;
    42     int m, n, p;
    43     int sum;
    44     getSg(1000);
    45     while (~scanf("%d%d%d", &m, &n, &p)) {
    46         if (m == 0 && n == 0 && p == 0) {
    47             break;
    48         }
    49         sum = sg[m] ^ sg[n] ^ sg[p];
    50         if (sum != 0) {
    51             printf("Fibo
    ");
    52         } else {
    53             printf("Nacci
    ");
    54         }
    55     }
    56     return 0;
    57 }
    View Code
  • 相关阅读:
    vue less使用/(除号/斜杠),浏览器不识别问题
    antDesignOfVue 表格复选框添加了默认选中状态,点击清空后数据清空,复选框的选中状态不变的问题。
    vue 可多选的日期插件
    antDesignOfVue 走马灯组件不自动定位到第一页
    antDesignOfVue 表格固定列之后出现空白列
    vue 动态添加表格列
    antDesignOfVue 符合条件的表格复选框禁止选中
    更换文件名大小写之后,git远程文件还存在,删除远程仓库的文件/文件夹
    git文件名大小写不敏感,更改文件大小写后无反应。
    记:mysql查询列含中文
  • 原文地址:https://www.cnblogs.com/gongpixin/p/5506497.html
Copyright © 2020-2023  润新知