【总结】博弈论

学习链接:
https://blog.csdn.net/jk_chen_acmer/article/details/82082653
https://blog.csdn.net/dgq8211/article/details/7602807
https://blog.csdn.net/YangHao5/article/details/88972326

取石子游戏 2
有一种有趣的游戏,玩法如下:

玩家:2人;

道具: N \rm{N} N堆石子,每堆石子的数量分别为 X \rm{X} X1, X \rm{X} X2, …… X \rm{X} Xn;

规则:

  1. 游戏双方轮流取石子;
  2. 每人每次选一堆石子,并从中取走若干颗石子(至少取1颗);
  3. 所有石子被取完,则游戏结束;
  4. 如果轮到某人取时已没有石子可取,那此人算负。
  5. 假如两个游戏玩家都非常聪明,问谁胜谁负?

定理

NIM博弈先手必胜,当且仅当 X \rm{X} X1 ^ X \rm{X} X2 ^ … ^ X \rm{X} Xn ≠ 0

#include <cstdio> //特殊情况:当全为0时,必败态,此时异或结果为0 //保持异或结果为零,最后每堆石子都变为零 //异或结果取决于每位上1的个数(奇数为1,偶数为0) //1.必胜态:异或结果不为0,不妨设为k,找出二进制下,在 k的有效最高位为 1 的一堆石子,改变它使k=0 //(此时小于原来个数,因为最高位由一变零,后面改变都不超过这一位)即可 //2.必败态:异或结果为0,因为是必胜态的下一步操作 const int MAXN = 1e5 + 5; int n, x, ans; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &x); ans ^= x; } if (ans == 0) printf("lose"); else printf("win"); }

「SEERC2019」Absolute Game

题目描述

Alice 和 Bob 在玩一个游戏。Alice 有一个包含 n \rm{n} n 个整数的数列 a \rm{a} a,Bob 有一个包含 n \rm{n} n个整数的数列 b \rm{b} b。每一回合中,玩家需要从他的数列中删去一个数字。玩家轮流进行回合,Alice 先手。

当两个数列中都只剩下一个数字的时候,游戏结束。令 Alice 的数列剩下的数字为 x \rm{x} x,Bob 的数列剩下的数字为 y \rm{y} y。Alice 想要最大化 x \rm{x} x y \rm{y} y之差的绝对值,而 Bob 想最小化这个值。两个玩家都以最优策略游戏。

请算出游戏结束时的结果。

分析:对A或B来说,均有两种选择:维护最优值或去掉最差值。每个人只会从自己最优的角度去游戏

  1. 首先假设A的策略是去掉最小值,则对 a \rm{a} a i \rm{i} i=1~n找到 b \rm{b} b j \rm{j} j使值最小。A会去掉n组中最小一组的 a \rm{a} a i \rm{i} i
  2. B有两种选择:
  • 维护最小值,因为这n组已经最小了,每个 a \rm{a} a i \rm{i} i对应一个最小值,A只能去掉n-1组,剩下一组是对B而言的最优结果
  • 将每个b配对去掉最大值,这样并不一定使B最终结果最小,因为它没有考虑A的策略,A至少去掉n-1组最小,很可能剩下一组最小所对应的b被B自己删去了,这样的策略不如前者
  1. 所以A每次会删去这n组中最大值,B每次会删去没有被a“匹配”到的b(因为b的数量比a多1,一定有剩余),答案就是n组最小中的最大值

那么为什么A不会维护最大值呢?因为B一定不会删去这n组最小值,假如A不删,最小值就会留到最后,这对A不利,因为结果不如前者

所以,本题思路是分别分析A和B,但彼此要考虑对方的策略,才能使自己的策略最优。这就是博弈论的思想

//frist try //错误代码,对B不利的策略 #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 1005; int n, a[MAXN], b[MAXN], t, tot, _min, _max; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= n; i++) scanf("%d", &b[i]); sort(a + 1, a + 1 + n); sort(b + 1, b + 1 + n); while (n != 1) { t = 0, _min = 1e9; for (int i = 1; i <= n; i++) { tot = 1e9; for (int j = 1; j <= n; j++) tot = min(tot, abs(a[i] - b[j])); if (tot < _min) t = i, _min = tot; } for (int i = t; i <= n - 1; i++) a[i] = a[i + 1]; t = 0, _max = -1; for (int i = 1; i <= n; i++) { tot = max(abs(b[i] - a[1]), abs(b[i] - a[n - 1])); if (tot > _max) t = i, _max = tot; } for (int i = t; i <= n - 1; i++) b[i] = b[i + 1]; n--; } printf("%d", abs(a[1] - b[1])); }
//second try //双方最优策略 #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 1005; int n, a[MAXN], b[MAXN], _min, _max = -1; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= n; i++) scanf("%d", &b[i]); for (int i = 1; i <= n; i++) { _min = 1e9 + 5; for (int j = 1; j <= n; j++) { _min = min(_min, abs(a[i] - b[j])); } _max = max(_max, _min); } printf("%d", _max); }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530424.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(17)  评论(0编辑  收藏  举报  
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示