博弈论进阶(3)
博弈论进阶
博弈“你那样看着我,就像你真的爱过我一样。”
函数拓展-
一、定义
相对于之前的游戏,这一次有了新的拓展。
我们给若干堆石子儿,再一次决策中如果一堆石子还可以取,那么我们就必须取。
定义如下:
游戏规定,对于还没有结束的单一游戏,游戏者必须对该游戏进行一步决策;
游戏的其他规则与普通 游戏相同
二、分析
对于这样的游戏,很显然我们会有这样的思路:
对于每一个单一的游戏 ,只需要让我们必胜的单一游戏尽可能玩的结束,必败的单一游戏尽早结束。
顺着这个思路想下去,我们可以做一个新的函数用于记录一个点最快或者最慢需要多少步走到终点。
当前状态节点为,后继结点为
如果是结束状态,;
对于必胜游戏,也就是的点,我们找到最慢的方式,而作为先手所选择的后续移动的状态一定是必败态,故是必败态;
对于必败游戏,即等于的点,需要找到最快的移动方式,后续为均为必胜状态,故。
总结一下:
定义了这个函数之后,贾志豪大佬给出了一个定理
对于 - 游戏先手必胜当且仅当单一游戏中最大的 为奇
数。
三、证明
这个定理非常好理解,游戏步数等于最多的单一游戏的步数,显然对于这个单一游戏的步数只要是奇数先手就可以赢。
当然这个证明是不严格的,下面就是来自 贾志豪 的严格证明:
我们要证明解法的正确性,需要证明三点:
- 对于所有的单一游戏,先手必胜状态的 值为奇数,先手必败状态的 值为偶数。
- 设最大的 为 ,那么胜手可以保证该单一游戏最少会在 步结束。
- 设最大的 为 ,那么胜手可以保证所有他必败游戏最多在 步结束。
证明一:
利用数学归纳法:
- 所有的终止状态的 值为 0,为先手必败状态。
- 假设状态树中某些状态点已经符合要求。我们找后继状态点已经全部被证明的状态点。
如果它是先手必败状态,那么它的后继状态都为先手必胜状态,后继状态的 值全为奇数,所以该状态点的 值为偶数。
如果它是先手必胜状态,那么它的后继状态中有先手必败状态,且它所有的先手必败的后记状态的 值为偶数,所以该状态点的 值为奇数。
证明二:
我们设 最大的单一游戏为 (如果有多个的话任取一个),最终的胜手为 。
总在 游戏处在先手必胜状态时去移动 的状态,且 可以保证他最多将该游戏的 值减小 1。①
对手总在 游戏处在先手必败状态时去移动 的状态,且对手最多将该游戏的 值减小 1。②
由①②得, 可以保证 游戏最少会在 步结束。
证明三:
我们设 最大的单一游戏为(如果有多个的话任取一个),最终的胜手为 。我们考虑除 外的任意一个他必败的单一游戏 。
在每一回合都可以将 的 值减少 1,将 带入先手必胜状态,对手必定将 的 至少减少 ,所以 可以保证 游戏最多会在 步结束。
四、一道题
GG and MM
题意:一共有个游戏,每一个游戏有两堆石子,一次移动可以从大的那堆石子里拿小的那堆石子的整数倍的石子。
只要是可以操作的游戏都要进行操作,不能进行操作的人负。
思路:
我们发现数据范围并不大,对于一个单一的游戏可以建一张表把所有的状态保留下来,进而使用这张表再建立一张表。最后再使用-结论即可。
这个子问题的正解为欧几里得博弈,对于每一对石子【】一定有,考虑的取值,发现大于等于我们就可以决定取得次数的奇偶性了,此时必胜。因为,所以,考虑的情况,发现只有一种转移的情况,此时可以参照之前的推理递归解决问题。下面的代码没有实现这一过程,具体实现可以写这一道题P1290
#include <bitset>
#include <vector>
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
#include <map>
#include <unordered_map>
using namespace std;
using namespace std;
#define lowbit(x) x&-x
#define ll int
#define pll pair<ll,ll>
#define dob double
#define For(i,s,n) for(ll i = s;i <= n;i++)
#define mem0(a) memset(a,0,sizeof a)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a/gcd(a,b)*b
#define abs(x) x>=0?x:-x
const int N = 1e3+50;
const double eps = 1e-6;
const ll mod = 1000000007;
const ll inf = 1e9+50;
ll sg[N][N],step[N][N];
void init(){
for(ll i = 0;i <= 1005;i++)sg[0][i] = step[0][i] = 0;//必败态
for(ll i = 1;i <= 1005;i++){
for(ll j = i;j <= 1005;j++){
sg[i][j] = 0;
for(ll k = 1;k*i<=j;k++){
ll x = min(i,j-i*k),y = max(j-i*k,i);
if(!sg[x][y])sg[i][j] = 1;//存在一个必败态,则为必胜态
}
if(sg[i][j]){//如果是必胜态
step[i][j] = -1;
for(ll k = 1;k*i<=j;k++){
ll x = min(i,j-i*k),y = max(j-i*k,i);
if(!sg[x][y])step[i][j] = max(step[i][j],step[x][y]);
}
step[i][j]++;
}
else{
step[i][j] = inf;
for(ll k = 1;k*i<=j;k++){
ll x = min(i,j-i*k),y = max(j-i*k,i);
step[i][j] = min(step[i][j],step[x][y]);
}
step[i][j]++;
}
}
}
}
int main(){
ios::sync_with_stdio(false);
init();
ll n;while(cin>>n){
ll ans = 0;
for(ll i = 1;i <= n;i++){
ll x,y;cin>>x>>y;
if(x>y)swap(x,y);
ans = max(ans,step[x][y]);
}
if(ans&1)puts("MM");
else puts("GG");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具