zoukankan      html  css  js  c++  java
  • 博弈——SG函数模板

      之前遇到博弈的题老是无从下手,今天学习了下博弈题的一个“小套路”,叫做Sprague-Grundy函数

    Sprague-Grundy函数定义为不出现在F(X)中每一个元素的Sprague-Grundy函数最小非负数。听着有点绕,其实举个例子就很好理解了。

    举例子前先说几个名词:

      x:当前状态量

      F(x):表示一个点能到达点的集合

      SG[]:0-n的SG函数值

      S[]:x后继状态的集合

      mex{}:表示最小的不属于这个集合的非负整数

    举个栗子:一堆n个的石头,每次只能取{1,3,5}个石头,先取完石头的赢。

      首先SG[0]=0是恒定不变的。

      x为1时,最多只能取1个石头了,取完之后剩0个,所以SG[1]=mex{SG[0]}=mex{0}=1;

      x为2时,最多只能取1个石头了,取完之后剩1个,SG[2]=mex{SG[1]}=mex{1}=0;

      x为3时,能取1个或3个,剩余2个或0个,SG[3]=mex{SG[0],SG[2]}=mex{0,0}=1;

      ...

    以上,就搞清楚了SG函数的计算了,然后看看有什么用呢?

    先打表看下0-9下对应的SG值

    然后我们不难发现:

      当SG值为0时,该状态为必败局面。

      当SG值非0时,该状态为必胜局面。

    这就很有用了!

    上面说的是一堆石头,当有几堆石头时可以类推出这样的处理:(别问我怎么推的,我也不知道╮(╯▽╰)╭

      SG[n1]^SG[n2]^SG[n3]^....^SG[nx]

      然后对它进行真值判断。


    上一道例题的代码 http://hdu.hustoj.com/showproblem.php?pid=1848

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 //SG打表
     4 const int N = 20;
     5 const int maxn = 1010;
     6 int F[N], S[maxn], SG[maxn];
     7 void getSG(int n)
     8 {
     9     int i, j;
    10     memset(SG, 0, sizeof(SG));
    11     for(i = 1; i <= n; i++)
    12     {
    13         memset(S, 0, sizeof(S));
    14         for(j = 0; F[j] <= i && j <= N; j++)
    15         {
    16             S[SG[i - F[j]]] = 1;    //标记
    17         }
    18         for(j = 0;; j++)
    19             if(!S[j])
    20             {
    21                 SG[i] = j;
    22                 break;
    23             }
    24     }
    25 }
    26 int main()
    27 {
    28     F[0] = 1;
    29     F[1] = 1;
    30     F[2] = 2;
    31     for(int i = 3; i <= 20; i++)
    32         F[i] = F[i - 1] + F[i - 2];
    33     getSG(1000);
    34     int m, n, p;
    35     while(cin >> m >> n >> p && m != 0 && n != 0  && p != 0)
    36     {
    37         /*
    38         if(SG[m]^SG[n]^SG[p])
    39             cout << "Fibo" << endl;
    40         else
    41             cout << "Nacci" << endl;
    42         */
    43         if((SG[m]^SG[n]^SG[p]) == 0)    //按位异或的优先级低于等值判定,怪不得交了几遍都是WA!!!
    44             cout << "Nacci" << endl;
    45         else
    46             cout << "Fibo" << endl;
    47         
    48     }
    49     return 0;
    50 }
  • 相关阅读:
    私有构造函数(C# 编程指南)
    unshift(), push(),shift(),pop()函数的运用
    flex转载
    二叉树各节点的实现
    关于删除树中指定节点的实例分析
    树的各种操作代码实现
    关于二叉查找树的++迭代器的实现
    利用map,以一个单词为键,以与它相差一个字母的单词组集作为值的算法编程
    逆向单项链表的算法
    给Vector类添加insert
  • 原文地址:https://www.cnblogs.com/friend-A/p/9141816.html
Copyright © 2011-2022 走看看