简单博弈论总结

简单博弈论

  • 本次简单博弈论讲解六个知识点:
    • 1:bash博弈;2:nim博弈;3:威佐夫博弈;4:Fibonacci博弈;5:sg函数;
  • 首先介绍博弈论问题有如下几个特点
    • 1:博弈模型为两人轮流决策的博弈。并且两人都使用最优策略来取得胜利。

      • 两个玩家,都会采取最优的决策,那么如果存在一个局面为必胜局面,某玩家位于此局面。只要自己无失误,则必胜。那么同样又一个局面为必败局面,某玩家位于此局面。只要对手无失误,则必败。
      • 那也就是说,针对这样的游戏,我们关注点应该在局面上。
    • 2:博弈是有限的。即无论两人如何决策,都会在有限步决出胜负。
    • 3:博弈是公平的。即两人进行决策的规则相同。
  • 相关概念:
    • 先手必胜状态:先手可以从这个状态走到某一个必败状态。
    • 先手必败状态:先手走不到任何一个必败状态。
    • 也就是说先手必胜状态,那么先手一定能采取某些操作,让后手面对必败态。如果是先手必败态,无论先手怎么操作,都无法让后手面对必败态。

bash博弈

  • 假设一堆石子有n个,每次最多取m个,甲乙两个玩家轮流取石子,最后把石子取完的人获胜,保证甲乙每一步的决策都是最优的,请问给定n和m,问甲胜还是乙胜。

    • 不妨假设刚刚开始n = m + 1,那么后手必胜,有如下结论:

      • n = ( m + 1 ) * r + s 其中(r > 1,0 <= s < m + 1)。如果s=0的话,先手每次取k个,后手只要取(m+1-k)个即可,后手必赢。如果s!=0的话,先手者第一次取s个,后手第一次取k个,接下来先手只要取(m + 1 - k)个即可,先手必赢。
      • 所以只需考虑 是否为0就可以判定结果。余为0,先手必败,反之必胜。
  • 例题:
    • hdu_2188
    • hdu_1846
    • hdu_1847

Nim游戏

  • 假设有n堆石子,每堆石子分别有\(a_1, a_2,…,a_n\)个,每次可以选择任意一堆且至少取1枚石子,
    甲乙两个玩家轮流取石子, 最后把石子取完的人获胜, 保证甲乙每一步的决策都是最优的, 甲为先手操作, 问甲胜还是乙胜。
  • 结论:
    • 设若\(a_1\land a_2\land ...\land a_n\)则先手必败, 反之必胜。
  • 证明:
    • 1):考虑极端情况, 当\(a_1, a_2,a_3...a_n\)全为0时, res = 0, 此时先手无法操作, 先手必败。
    • 2):当\(res = x ≠ 0\)时,我们取\(res\)最高位\(1\),设最高位\(1\)为第\(k\)位,则一定存在\(a_i\)第\(k\)位为\(1\)。对于此,我们可以反证, 若\(a\)中所有第\(k\)位全为\(0\), 则\(res\)第\(k\)位也为\(0\), 矛盾。
    • 所以我们让\(a_i\land x, 我们可以得出\)\(a_i\land x < a_i\)。那么我们完全可以从\(a_i\)中拿走\(a_i\land x\), 即\(a_i -a_i\land x>0\), 最后剩下\(a_i -(a_i -a_i\land x) = a_i\land x\);
    • 此时后手的局面为\(res = a_1 \land a_2\land ,…,\land a_i\land x,…,\land a_n=x\land x=0\)
    • 即先手通过一定的操作让后手面对\(res=0\)的情况。
    • ?3): 当\(res = x = 0\)且\(a\)不全为\(0\)时, 我们无法通过任何操作让下一个状态的\(res\)也为\(0\)。这一步的证明可以采用反证法。

      ?若存在$a_i \(拿走一定的石子变为\)a_i^′$且res不变。

      ?在目前状态\(res= a_1\land a_2\land ,…,\land a_i\land ,…,\land a_n=0\)设为①式。

      ?在下个状态\(res= a_1\land a_2\land ,…,\land a_i^′\land ,…,\land a_n=0\)设为②式。

      ?$①\land ② $= \(0\land 0\) => $ a_i\land a_i^′ = 0$

      ?即\(a_i= a_i^′\), 与假设矛盾。

  • 综上所述, 当\(a\)不全为\(0\)时, 任意一个\(res != 0\)的局面, 先手可以通过一定的操作让后手面对\(res = 0\)的局面。
  • 对于任意一个\(res = 0\)的局面, 先手无法通过任何操作让后手面对\(res = 0\)的局面。
  • 得出结论, 当\(res = 0\)时先手必败, 反之必胜。

Nim博弈拓展-台阶Nim

  • 问题描述: 有一个\(n\)级台阶的楼梯, 每级台阶上有若干个石子, 其中第i级台阶上有\(a_i\)个石子\((i≥1)\)。两位玩家路轮流操作, 每次操作可以从任意一级台阶上拿若干个石子放到下一级台阶上(不能不拿)。
  • 已经拿到地面的石子不能再拿, 最后无法进行操作的人视为失败。
  • 问如果两人都采取最优策略, 先手是否必胜.
  • 结论
    • \(res= a_1\land a_3\land a_5\land ,…,\land a_n=0\)(当然这里的n是奇数)先手必败, 反之先手必胜。
  • 证明
  • 1): 考虑极端情况, 当\(a_1, a_3,…,a_n\)全为0时, \(res = 0\), 此时先手只能将偶数级台阶往下搬, 后手只需要将先手从偶数级台阶上搬下来的石子全部搬到下一级偶数级台阶, 先手必败。
  • 2): 当\(res = x ≠ 0\)时, 通过经典Nim游戏的证明, 我们知道一定有一种方法搬一定的石子到下一级让后手面对res为0的局面。
  • 3):当\(res = x = 0\)且\(a\)不全为\(0\)时, 我们无法通过任何操作让下一个状态的\(res\)也为\(0\)。
  • 即对于\(res\)不为\(0\)的情况, 先手总能通过一定的操作让后手面对\(res\)为\(0\)的情况,。
  • 然而\(res\)为\(0\)时, 先手无论做什么操作都无法让后手面对\(res\)为\(0\)的情况。
  • 那么此刻我们就将题目转化为在奇数台阶上的经典Nim游戏。
  • 思考题:
  • 为什么不用\(res= a_2\land a_4\land a_6\land ,…,\land a_n=0\)(n为偶数)来判定胜负?
    • 因为当先手搬去一定的石子让后手面对\(res=0\)的情况, 后手可以搬去一号台阶的石子到地面让先手重新面对\(res=0\)的情况
  • 例题:
    • hdu_1850(经典Nim)
    • #include<bits/stdc++.h>
      using namespace std;
      const int maxn = 100 + 10;
      int n, a[maxn], res;
      int main()
      {
          while(cin >> n)
          {
              if(!n) break;
              res = 0;
              for(int i = 1; i <= n; i++)
              {
                  cin >> a[i];
                  res ^= a[i];
              }
              if(res == 0) puts("0");
              else
              {
                  int ans = 0;
                  for(int i = 1; i <= n; i++)
                  {
                      if((res ^ a[i]) < a[i]) ans ++;
                  }
                  cout << ans << endl;
              }
          }
          return 0;
      }
    • hdu_1730(经典Nim)
    • #include<bits/stdc++.h>
      using namespace std;
      int main()
      {
          int n, m;
          while(cin >> n >> m)
          {
              int res = 0;
              for(int i = 1; i <= n; i++)
              {
                  int a, b; cin >> a >> b;
                  res = res ^ (abs(a - b) - 1);
              }
              if(res == 0) puts("BAD LUCK!");
              else puts("I WIN!");
          }
      }
    • poj_1704(台阶Nim)
    • #include<iostream>
      #include<cstdio>
      #include<algorithm>
      #include<cstring>
      using namespace std;
      const int maxn = 1000 + 10;
      int a[maxn], d[maxn];
      int main()
      {
          int T; cin >> T;
          while(T--)
          {
              int n; cin >> n;
              for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
              sort(a + 1, a + 1 + n);
              for(int i = 1; i <= n; i++)
                  d[i] = a[i] - a[i - 1] - 1;
              int res = 0;
              for(int i = n; i > 0; i -= 2)
                  res ^= d[i];
              if(res) puts("Georgia will win");
              else puts("Bob will win");
          }
          return 0;
      }
    • hdu_4315(台阶Nim)
    • #include<bits/stdc++.h>
      using namespace std;
      const int maxn = 1e3 + 10;
      int a[maxn];
      int n, k;
      int main()
      {
          while(cin >> n >> k)
          {
              memset(a, 0, sizeof a);
              for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
              if(k == 1) puts("Alice");
              else
              {
                  int res = 0;
                  if(n & 1)
                  {
                      if(k == 2) res ^= a[1] - 1;
                      else res ^= a[1];
                      for(int i = 3; i <= n; i += 2)
                          res ^= a[i] - a[i - 1] - 1;
                  }
                  else
                  {
                      for(int i = 2; i <= n; i += 2)
                          res ^= a[i] - a[i - 1] - 1;
                  }
                  if(res) puts("Alice");
                  else puts("Bob");
              }
          }
          return 0;
      }

Wythoff 游戏 (威佐夫博弈)

  • 两堆石子各有若干个, 两人轮流从一堆取至少一个石子或从两堆取同样多的物品, 最后一名取完石子者胜利。
  • 结论:
    • 当两堆石子各有\(n\)和\(m\)个且不妨设\(n<m\)。
    • 当\((m-n) \frac{√5+1}{2}=n\)时, 先手必败。
  • 证明
  • ?首先考虑最(zhao)极(gui)端(lv)的情况, (0, 0), (1, 2), (3, 5)局面为先手必败局面。而且这样的数字对被称为奇异局势。
  • 奇异局势的定义如下:
    • 设数字对为\([a(i), b(i)]\)
    • 1:$ a(0) = b(0) = 0$;
    • 2: \(a(k)\)是前面数字对中未出现的最小的自然数, 且\(a(k)+k=b(k)\)。
  • 接下来我们看奇异局势的几个性质:
    • 性质1: 任何自然数都包含在一个且仅有一个奇异局势中。
    • 性质2: 任意操作都能将奇异局势转变为非奇异局势.
    • 性质3: 采取适当的方法, 可将非奇异局势转变为奇异局势。

      证明略

  • 结论:奇异局势必败
    • 接下来我们看详细证明:
    • 首先要明白Betty定理: \(\frac{1}{a}+\frac{1}{b}=1\),(\(a, b\)为无理数), 则有集合\(P{[at]}\)和集合\(Q{[bt]}\)会不重复的覆盖掉所有正整数。(\(t\)为任意正整数, \([]\)运算为取整数运算)(Betty证明略)
    • 奇异局势有如下命题:
      • (1): \(a(n+1)\)是前\(n\)组必败态中未出现的最小正整数;

        • 如果\(a(n+1\))不是前\(n\)组未出现的必败态中最小的正整数,则可以\(a(n+1)\)走到\(a\)更小的状态, 与我们寻找必败态的方式矛盾。
      • (2):$ a(k)+k=b(k)$
        • 归纳法:$ (0,0)\(为必败态;若前k个必败态为\)(a(k),a(k)+k)\(, 证:下一个必败态为\)(a(k+1),a(k+1)+k+1)$。
        • 从\(k+1\)出发, 一共可能走向三类状态, 从左边拿一些, 从右边拿一些,从两边拿一样多的石子。
          • 情况1: \(a\)少了, 由命题\(1\)可知, 比\(a\)小的任意一个必败态都出现过, 所以后手可以从\(b\)中取一定量的石子让先手重新面临必败态。
          • 情况2: 与情况1类似
          • 情况3: 同时拿走一定的石子, 假设拿完之后变为\((a(m), a(m)+k+1)\), 后手只需拿走一定数量的石子让先手面对\((a(m), a(m) + m)\)这样的局面。
        • 所以成立
    • 接下来我们用Betty定理来求出a, b差值与a的关系
    • 我们知道\(a+n=b\)
    • \(at=[αt], bt=[βt]\)
    • 则有at+t=[(α+1)t] =[βt]
    • \(\frac{1}{α+1}+\frac{1}{α}=1\)推出\(α^2-α-1=0\)
    • 解方程得\(α=\frac{√5+1}{2}\)
    • 即我们找到了必败态的通式, 即\(α?(b-a)=a\)
  • 例题
    • hdu_2177
    • #include<bits/stdc++.h>
      using namespace std;
      int n, m;
      
      bool check(int n, int m)
      {
          int x = min(n, m), y = max(n, m);
          double c = (sqrt(5.00000) + 1) / 2;
          double d = (double)(y - x);
          if(x == int(c*d)) return 1; // 必败
          return 0;
      }
      
      void work()
      {
          if(n > m) swap(n, m); // (n, m)
          //第一个模块 我们能一起减去让他成为必败态
          {
              int tem = m - n;
              double c = (sqrt(5.00000) + 1) / 2;
              int a = double(tem) * c;
              int b = a + tem;
              if(n - a == m - b) cout << a << " " << b << endl;
          }
          //第二个模块 我们求出当前n的奇异局势, 如果m比他大 拿走就行
          //如果m比他小我们求出(x, n) 然后拿走m
          {
              double c = (sqrt(5.00000) + 1) / 2;
              int x = n;
              double d = x / c;
              int y = n + d;
              if(m > y) cout << x << " " << y << endl;
              else
              {
                  double x = double(n) * 2 / (sqrt(5.000000) + 1);
                  cout << int(x) << " " << n << endl;
              }
          }
      }
      
      int main()
      {
          while(cin >> n >> m)
          {
              if(!(n + m)) break;
              if(check(n, m)) puts("0");
              else
              {
                  puts("1");
                  work();
              }
          }
          return 0;
      }
      

斐波那契博弈(Fibonacci Nim Game)

  • 一堆石子有\(n\)个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完。以后每次取的石子数不能超过上次取子数的\(2\)倍。取完者胜。给定\(n\),问先手必胜还是必败。
  • 结论:
    • 当\(n\)为\(fibonacci\)数的时候,先手必败
  • 证明:
    • 采用归纳法证明:
    • 首先: 将\(n\)记为\(f(i)\);
    • 我们考虑最极端的情况当\(n=1\)时, 先手无法全部取完, 必败; \(n=2\)时, 先手只能取一枚石子, 必败。同时对于任意一个\(n\)先手都不能取\(n/3\)以上的石子, 因为这样先手也将必败。
    • 假设\(i≤k\)时, 结论成立, 当\(i=k+1\)时,$ f(i)=f(k)+f(k-1)$

      首先我们明确, 对于\(fibonacci\)数列, 有如下几个不等式:

      • \(1: f(k-1)<2f(k)<f(k+1):\)
      • \(2: 3f(k-1)>f(k+1)\)
      • \(3:4f(k-1)<3f(k)\)
      • \(4: 2f(k-1)>f(k)\)
    • 我们可以将\(f(i)\)分解为\(f(k)\)和\(f(k-1)\)两堆石子。基于第一个不等式, 我们得知先手无法一次拿完所有的\(f(k-1)\)。同时基于假设, 在f(k-1)中先手必败, 则后手将取完所有石子同时余下\(f(k)\)个石子。
    • 对于余下的\(f(k)\)个石子, 由不等式三可以得出先手无法全部拿光\(f(k)\), 根据假设可知\(f(k)\)先手必败, 所以总局面先手必败。
    • 当\(n\)不为\(fibonacci\)数时, 根据\(Zeckendorf\)定理(齐肯多夫定理)(任意一个数字都可表示为若干个不连续的斐波那契数之和), 先手可取一定的石子让后手面对\(fibonacci\)数
  • 例题:
    • hdu_2516
    • #include<bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      unordered_map<int, int> mp;
      ll f[50];
      void fib()
      {
          f[0] = f[1] = 1;
          for(int i = 2; i <= 50; i++)
          {
              f[i] = f[i - 1] + f[i - 2];
              mp[f[i]]++;
          }
      }
      
      int main()
      {
          int n;fib();
          while(cin >> n)
          {
              if(n == 0)break;
              if(!mp[n]) puts("First win");
              else puts("Second win"); //如果是fibonacci数, 则先手必败
          }
          return 0;
      }
      

SG函数

  • \(mex\)运算:
    • 定义\(mex(S)\)为不属于集合S的最小非负整数运算。

      • ?举个栗子: \(S={1, 2, 3}, mex(s) = 0\);
  • SG函数:
    • SG函数: 设对于每个节点x, 设从x出发有k条有向边分别到达节点\(y_1 ,y_2,…,y_k\), 定义SG(x)函数为后继节点\(y_1 ,y_2,…,y_k\)的\(SG\)函数值构成的集合再执行\(mex\)运算的结果。
    • 特别的, 整个有向图\(G\)的\(SG\)函数被定义为有向图起点\(s\)的\(SG\)函数值, 即\(SG(G)=SG(s)\)
    • 有向图终点的\(SG\)函数为\(0\)。
  • 结论:
    • ?先手必败, 则该局面对应\(SG\)函数\(=0\)。反之必胜。
  • 简单证明:
    • 考虑极端情况: 若某个结点棋子不能移动, 即当前处于终点无法移动, 此时\(SG\)值为\(0\), 对应必败状态。
    • 若某个结点的后继节点的\(SG=0\), 则在后继节点\(mex\)运算后该节点的值大于\(0\) 这等价于一个局面后面存在必败局面, 则当前局面为必胜局面。
    • 若某个节点所有后继节点的\(SG≠0\), 在\(mex\)运算后, 该节点的\(SG\)值为\(0\), 即某一个局面后继节点全部为必胜局面, 则当前局面为必败局面。
  • 推广:
    • 当然我们有时候面对的不止是一个有向图上的博弈, 可能是多个图上的博弈。
    • ?对于多个有向图: 令\(res=SG(s_1 )\land SG(s_2 )\land … \land SG(s_n);\)
    • 若\(res=0\), 则总局面必败。
    • 若\(res≠0\), 则总局面必胜。
    • 证明与经典\(Nim\)游戏类似, 不在赘述。
  • 例题
    • hdu_1524
    • #include<bits/stdc++.h>
      using namespace std;
      const int maxn = 1e3 + 10;
      int n, num;
      int sg[maxn];
      
      int head[maxn], ver[maxn], nex[maxn], tot;
      void add(int x, int y)
      {
          ver[++tot] = y; nex[tot] = head[x]; head[x] = tot;
      }
      
      int GetSg(int x)
      {
          if(sg[x] != -1) return sg[x];
          bool vis[maxn];
          memset(vis, 0, sizeof(vis));
          for(int i = head[x]; i; i = nex[i]) // 扫描所有出边
          {
              int y = ver[i];
              sg[y] = GetSg(y);
              vis[sg[y]] = 1; //所有出边的sg函数值
          }
          for(int i = 0; i < n; i++)
              if(!vis[i]) return sg[x] = i; // mex运算
          return 0;
      }
      
      void init()
      {
          memset(head, 0, sizeof(head));
          memset(nex, 0, sizeof nex);
          memset(ver, 0, sizeof ver);
          memset(sg, -1, sizeof sg);
          tot = 0;
      }
      
      int main()
      {
          while(cin >> n)
          {
              init();
              for(int i = 0; i < n; i++)
              {
                  cin >> num;
                  while(num--)
                  {
                      int x; scanf("%d", &x);
                      add(i, x);
                  }
              }
              while(cin >> num)
              {
                  if(!num) break;
                  int res = 0;
                  while(num--)
                  {
                      int x; scanf("%d", &x);
                      res ^= GetSg(x);
                  }
                  if(res) puts("WIN");
                  else puts("LOSE");
              }
          }
          return 0;
      }
      
    • hdu_1536
      #include<bits/stdc++.h>
      using namespace std;
      const int maxn = 1e4 + 10;
      int s[maxn], sg[maxn];
      int k;
      
      void init()
      {
          memset(sg, -1, sizeof(sg));
      }
      
      int GetSg(int x)
      {
          if(sg[x] != -1) return sg[x];
          bool vis[maxn]; memset(vis, 0, sizeof(vis));
          for(int i = 1; i <= k; i++)
              if(x >= s[i])
              {
                  sg[x - s[i]] = GetSg(x - s[i]);
                  vis[sg[x - s[i]]] = 1;
              }
          for(int i = 0; ; i++)
              if(!vis[i]) return sg[x] = i;
          return 0;
      
      }
      
      int main()
      {
          ios::sync_with_stdio(false);
          while(cin >> k)
          {
              init();
              if(k == 0) break;
              for(int i = 1; i <= k; i++) cin >> s[i];
              int num; cin >> num;
              while(num--)
              {
                  int x, res = 0; cin >> x;
                  for(int i = 1; i <= x; i++)
                  {
                      int y; cin >> y;
                      res ^= GetSg(y);
                  }
                  if(res) cout << "W";
                  else cout << "L";
              }
              cout << endl;
          }
          return 0;
      }
      

原文地址:https://www.cnblogs.com/zxytxdy/p/11619871.html

时间: 2024-10-16 06:17:16

简单博弈论总结的相关文章

简单博弈论总结加例题解析

(一)巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.最后取光者得胜. 显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜.因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜.总之,

LeetCode 5024 除数博弈 --(简单博弈论)

今天在LeetCode的看到一到题目 这道题目有点坑,没有思路的话容易钻牛角. 刚刚开始时,我想的是直接用while循环来模拟计算,后来觉得这么好麻烦,也有复制的逻辑在里面.后面我推导了一下 以下是我的推导过程,爱丽丝简称 A 鲍勃 简称B 当num=2时,A=1-->num=num-1=1,A赢 当num=3时,A只能出1,-->num=num-1=2,此时B正好处于num=2的情况,所以B可以用之前A的策略,B赢 当num=4时,A可以出1 或 2,但是为了赢,A必须让B处于输的情况,也就

简单博弈论取石子

有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍或是围棋子等等均可.两个人轮流从堆中取物体若干,规定最后取光物体者取胜.这是我国民间很古老的一个游戏,别看这游戏极其简单,却蕴含着深刻的数学原理.下面我们来分析一下要如何才能够取胜. (一)巴什博弈(Bash Game,同余理论):只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.最后取光者得胜. 显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜.

【算法】简单博弈论

巴什博弈 (bash game) 题型 仅有一堆n个物品,两个人轮流取1~m个,最后取的人胜(不能取的人输) 分析 总体可分几种情况 $n=0$,先手输 $0<n<=m$,先手胜 $n=m+1$,先手输 $n=k*(m+1)+r$,先手胜(先手取走r个,给后手留下k*(m+1)的局面) $n=k*(m+1)$,先手输 代码 int Bash_Game(int n,int m) //是否先手有必赢策略 { if(n==0) return 0; if(n%(m+1)!=0) return 1; r

BZOJ 2463 谁能赢呢? (博弈论)

题解:简单博弈论 #include <cstdio> int main(){ int n; while(scanf("%d",&n),n!=0) if (n&1) puts("Bob"); else puts("Alice"); return 0; } BZOJ 2463 谁能赢呢? (博弈论),布布扣,bubuko.com

URAL 1639 Chocolate 2 (博弈论)

1639. Chocolate 2 Time limit: 1.0 second Memory limit: 64 MB Little Boy is mad at Karlsson, who ate all the sweets in the flat and even went to the neighbours to eat their sweets too. Now Little Boy's parents brought home a chocolate bar, and, sure e

博弈论 (学习中……持续更新)

博弈论 以下主要内容来自于对集训队论文<组合游戏略述--浅谈SG游戏的若干拓展及变形>的整理与从其他地方收集补充的一些经典模型 博弈论还在学习过程中,可能还会补充一些东西 组合游戏基础定义 游戏的定义: 游戏有2名参与者,两人轮流操作 游戏过程中的任意时刻有确定的状态 参与者操作时将游戏从当前状态转移到另一状态,且规则规定了在任意状态时,可以到达的状态集合 在有限步数之内结束(没有平局) 参与者拥有完全的信息 游戏的表示: 定义:对于一个游戏,如果当前状态\(P\),玩家\(L\)可以转移到的

教官的游戏

[题目描述] 有N个学生刚吃完饭,准备出食堂,学校有个规矩:必须2人一排或3人一排离开. 两个教官A,B轮流取2或3人,谁先取完谁就赢得游戏(A先取). 若两人都采用最优策略,询问谁会赢. [输入描述] 一个整数N. [输出描述] A赢输出1: B赢输出-1: 平局输出0: 若人数为负,输出120. [样例输入] 7 [样例输出] 1 [数据范围及提示] N <= 10000. 源代码: #include<cstdio> int n; int main() //显而易见的简单博弈论. {

[您有新的未分配科技点]博弈论进阶:似乎不那么恐惧了…… (SJ定理,简单的基础模型)

这次,我们来继续学习博弈论的知识.今天我们会学习更多的基础模型,以及SJ定理的应用. 首先,我们来看博弈论在DAG上的应用.首先来看一个小例子:在一个有向无环图中,有一个棋子从某一个点开始一直向它的出点移动,双方轮流操作,无法操作者输,问是否先手必胜. 考虑一下我们之前的Nim游戏,如果我们把后继状态看成后继点的话,不难发现Nim游戏的互相转移也是一个DAG.因此,DAG上出度为0的点的sg值为0,再用上一篇博客提到的mex操作来求每个点的值就可以了(注意,这并不是一个"大"子图,不能