先开个坑 简单写下公式,推导(不一定会写)和拓展应用慢慢补充
1.三种博弈
1.1.巴什博弈
简介:n个物品 双方每次取x个(1<=x<=k),最后一个取得物品的人获胜。
最优策略:
如果n%(k+1)=0的时候先手必败
否则先手先取 n%(k+1) 随后与对手所取的物品量的和维持(k+1)就可获胜。
1.2.威佐夫博弈(维基)
简介:有两堆物品。两方轮流从一堆或两堆中拿走物品。在拿物品时有两种方法:其一是从两堆拿走相同量的物品;其二是从其中一堆拿走任意量的物品。
最后一个取得物品的人获胜。
最优策略:
游戏过程中的任何状态都可用一对正整数(n,m)来表示,其中n≤m,分别表示两堆筹码的数目。所有状态分为两种:先手必胜和后手必胜。在双方均采取最佳策略的情况下,前者表示下一个行动的玩家将取胜,后者表示下一个行动的玩家将落败。可见,游戏的最佳策略是从一个先手必胜状态移动到任一后手必胜状态。
对于任一状态(n,m),可用以下法则递归地判断此状态是先手必胜还是后手必胜:
1.(0,0)为后手必胜状态。 2.若一个状态的后续中存在后手必胜状态,则该状态为先手必胜。 3.若一个状态的全部后续均为先手必胜,则该状态为后手必胜。
例如,由上述第一条、第二条可推出对所有的正整数m,(0,m)和(m,m)均为先手必胜状态。
而(1,2)是后手必胜状态,因为它的后续(0,1)、(0,2)和(1,1)均为先手必胜状态。
前几个后手必胜状态为(0,0)、(1, 2)、(3, 5)、(4, 7)、(6,10)和(8, 13)。
上图是威佐夫游戏中的后手必胜状态。以左下角为原点向右、上为正方向建立坐标系,以红色标出的小正方形右上角的顶点坐标即为后手必胜状态(看看就行)
最优策略
后手胜利时,设横坐标n纵坐标m,形成的序列为N和M 通项公式如下:
在OEIS上的这两个序列N , M
黄金分割的值Φ= (1+sqrt(5))/2
1.3 NIM博弈(维基)
简介:
游戏者轮流从几排棋子(或者任何道具)中选择一排,再由这一排中取走一个或者多个,依规则不同,拿走最后一个的可能是输家,也有可能是赢家。当指定相应数量时,一堆这样的棋子称作一个尼姆堆.
如下是当有3排棋子 数量分别为3 4 5时的一种游戏情况
a.当拿走最后一个棋子胜利时(normal版本):
如果所有堆中的异或和为0 ,后手胜利
否则先手胜利
期望最后一排剩下偶数个
b.当拿走最后一个棋子失败时(misère版本):
其他的策略一致,期望最后一排剩下奇数个
如果异或和为0,后手胜利
2.SG函数
SG(x)=MEX{f(y)|y时x的后继}
a.dfs
//注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍
//n是集合s的大小 S[i]是定义的特殊取法规则的数组
int s[110],sg[10010],n;
int SG_dfs(int x)
{
int i;
if(sg[x]!=-1)
return sg[x];
bool vis[110];
memset(vis,0,sizeof(vis));
for(i=0;i<n;i++)
{
if(x>=s[i])
{
SG_dfs(x-s[i]);
vis[sg[x-s[i]]]=1;
}
}
int e;
for(i=0;;i++)
if(!vis[i])
{
e=i;
break;
}
return sg[x]=e;
}
b.顺序检索
//f[]:可以取走的石子个数
//sg[]:0~n的SG函数值
//hash[]:mex{}
int f[N],sg[N],hash[N];
void getSG(int n)
{
int i,j;
memset(sg,0,sizeof(sg));
for(i=1;i<=n;i++)
{
memset(hash,0,sizeof(hash));
for(j=1;f[j]<=i;j++)
hash[sg[i-f[j]]]=1;
for(j=0;j<=n;j++) //求mes{}中未出现的最小的非负整数
{
if(hash[j]==0)
{
sg[i]=j;
break;
}
}
}
}
SG定理
sg(X) = sg(x[1]) ^ sg(x[2]) ^ … ^ sg(x[n])