*模板--博弈

  1 //SG函数打表
  2 const int MAX_DIG = 64;
  3 
  4 //  SG打表
  5 //  f[]:可以取走的石子个数
  6 //  sg[]:0~n的SG函数值
  7 //  hash[]:mex{}
  8 int f[MAX_DIG];
  9 int sg[MAX_DIG];
 10 int hash[MAX_DIG];
 11 
 12 void getSG(int n)
 13 {
 14     memset(sg, 0, sizeof(sg));
 15     for (int i = 1; i <= n; i++)
 16     {
 17         memset(hash, 0, sizeof(hash));
 18         for (int j = 1; f[j] <= i; j++)
 19         {
 20             hash[sg[i - f[j]]] = 1;
 21         }
 22         for (int j = 0; j <= n; j++)    //  求mes{}中未出现的最小的非负整数
 23         {
 24             if (hash[j] == 0)
 25             {
 26                 sg[i] = j;
 27                 break;
 28             }
 29         }
 30     }
 31 }
 32 
 33 //SG DFS
 34 const int MAX_DIG = 64;
 35 
 36 //  DFS
 37 //  注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍
 38 //  n是集合s的大小 S[i]是定义的特殊取法规则的数组
 39 int s[MAX_DIG];
 40 int sg[MAX_DIG * 100];
 41 int n;
 42 
 43 int SG_dfs(int x)
 44 {
 45     if (sg[x] != -1)
 46     {
 47         return sg[x];
 48     }
 49     bool vis[MAX_DIG];
 50     memset(vis, 0, sizeof(vis));
 51     for (int i = 0; i < n; i++)
 52     {
 53         if (x >= s[i])
 54         {
 55             SG_dfs(x - s[i]);
 56             vis[sg[x - s[i]]] = 1;
 57         }
 58     }
 59     int e;
 60     for (int i = 0; ; i++)
 61     {
 62         if (!vis[i])
 63         {
 64             e = i;
 65             break;
 66         }
 67     }
 68     return sg[x] = e;
 69 }
 70 
 71 
 72 //BASH博弈
 73 //巴什博奕:只有一堆n个物品,两个人轮流从中取物,规定每次最少取一个,最多取m个,最后取光者为胜。
 74 #include <iostream>  
 75 using namespace std;  
 76 int main()  
 77 {  
 78     int n,m;  
 79     while(cin>>n>>m)  
 80       if(n%(m+1)==0)  cout<<"后手必胜"<<endl;  
 81       else cout<<"先手必胜"<<endl;  
 82     return 0;  
 83 }  
 84 
 85 //威佐夫博弈(Wythoff Game):
 86 //有两堆各若干的物品,两人轮流从其中一堆取至少一件物品,至多不限,或从两堆中同时取相同件物品,规定最后取完者胜利。
 87 //直接说结论了,若两堆物品的初始值为(x,y),且x<y,则另z=y-x;
 88 //记w=(int)[((sqrt(5)+1)/2)*z  ];
 89 //若w=x,则先手必败,否则先手必胜。
 90 
 91 /*
 92 尼姆博弈(Nimm Game):
 93 尼姆博弈指的是这样一个博弈游戏:有任意堆物品,每堆物品的个数是任意的,双方轮流从中取物品,每一次只能从一堆物品中取部分或全部物品,最少取一件,取到最后一件物品的人获胜。
 94 结论就是:把每堆物品数全部异或起来,如果得到的值为0,那么先手必败,否则先手必胜。
 95 */
 96 
 97 /*
 98 斐波那契博弈:
 99 有一堆物品,两人轮流取物品,先手最少取一个,至多无上限,但不能把物品取完,之后每次取的物品数不能超过上一次取的物品数的二倍且至少为一件,取走最后一件物品的人获胜。
100 结论是:先手胜当且仅当n不是斐波那契数(n为物品总数)
101 */
View Code
原文地址:https://www.cnblogs.com/yijiull/p/7726261.html