一.典型的博弈模型:
Nim博弈的一些思考:
1.无法进行任何移动的局面(也就是 (terminal position) )是 (P-position);
2.对于 (P-position),一定存在某种方式可以移动到 (N-position) 的局面;
3.对于 (N-position),所有移动都导致 (P-position) 的局面。
证明:
1.((0,0)) 为无法移动的状态,且为 (P-position) ;
2.
令 (t=a_1 igoplus a_2 igoplus ... igoplus a_n!=0),为当前状态。
假设 (a_i o a_i^{'}),使得 (a_1 igoplus a_2 igoplus ...igoplus a_i^{'} igoplus ... igoplus a_n=0)
必然会有一个 (a_i) 使 (t) 的二进制最高位是 (1),且 (a_i igoplus t<a_i)。
那么令 (a_i^{'}=a_i igoplus t),有
(a_1 igoplus a_2 igoplus ...igoplus (a_i igoplus t) igoplus ... igoplus a_n=0)
得证。
3.
(a_1 igoplus a_2 igoplus ...igoplus a_i igoplus ... igoplus a_n=0)
假设 (a_i o a_i^{'}),则
(a_1 igoplus a_2 igoplus ...igoplus a_i^{'} igoplus ... igoplus a_n=0)
所以 (a_i=a_i^{'})。
当把 (a_i) 取走之后,剩余的数量的异或和等于 (a_i),为 (P-position)。
不满足要求。
二.一般的博弈:
1.(N/P)分析:
(P)点:必败点,无论谁处于此位置,则在双方操作正确的情况下必败。
(N)点:必胜点,处于此情况下,双方操作均正确的情况下必胜。
必胜点和必败点的性质:
1、所有终结点是 必败点 (P) 。(我们以此为基本前提进行推理,换句话说,我们以此为假设)
2、从任何必胜点 (N) 操作,至少有一种方式可以进入必败点 (P)。
3、无论如何操作,必败点 (P) 都只能进入必胜点 (N)。
我们研究必胜点和必败点的目的时间为题进行简化,有助于我们的分析。通常我们分析必胜点和必败点都是以终结点进行逆序分析。这种分析方法可以帮助我们从以下题目中寻找到规律。
例题:
1.hdu1847
2.hdu2147
2.(SG)函数的运用:
(Sprague-Grundy)定理((SG)定理):
游戏和的 (SG) 函数等于各个游戏 (SG) 函数的 (Nim)和(各个数相异或的结果)。这样就可以将每一个子游戏分而治之,从而简化了问题。而 (Bouton) 定理就是 (Sprague-Grundy) 定理在(Nim)游戏中的直接应用,因为单堆的 (Nim) 游戏 (SG) 函数满足 (SG(x) = x)。
(SG)函数:
先定义 (mex(minimal excludant)) 运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。
例如(mex{0,1,2,4}=3)。
对于任何状态 (x),(SG[x]=mex{S}),其中 (S) 为 (x) 的后继状态的 (SG) 函数值的集合。比如 (x) 的后继状态有 (a,b,c),那么(SG[x]=mex{SG[a],SG[b],SG[c]})。
集合(f)表示到达其后继状态的途径。
例子:
比如有一堆石子 (n) 个,每次可以取({1,3,4})个,那么个数的(SG)函数值:
(SG[0]=0),为最终态。
(x=1) 时,(f={1}),后继状态:({0}),所以 (SG[1] = mex{ SG[0] }= mex{0} = 1);
(x=2) 时,(f={1}),后继状态:({1}),所以 (SG[2] = mex{ SG[1] }= mex{1} = 0);
(x=3) 时,(f={1,3}),后继状态:({0,2}),所以 (SG[3] = mex{SG[0],SG[2]}= mex{0,0} = 1);
(x=4) 时,(f={1,3,4}),后继状态:({0,1,3}),所以 (SG[4] = mex{ SG[0],SG[1],SG[3] }= mex{0,1,1} = 2);
求解 (SG)函数代码:
//f[N]:可改变当前状态的方式,N为方式的种类,f[N]要在getSG之前先预处理
//SG[]:0~n的SG函数值
//S[]:为x后继状态的集合
int f[N],SG[MAXN],S[MAXN];
void getSG(int n){
int i,j;
memset(SG,0,sizeof(SG));
//因为SG[0]始终等于0,所以i从1开始
for(i = 1; i <= n; i++){
//每一次都要将上一状态 的 后继集合 重置
memset(S,0,sizeof(S));
for(j = 0; f[j] <= i && j <= N; j++)
S[SG[i-f[j]]] = 1; //将后继状态的SG函数值进行标记
for(j = 0;; j++) if(!S[j]){ //查询当前后继状态SG值中最小的非零值
SG[i] = j;
break;
}
}
}
例题:Fibonacci again and again HDU - 1848
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=19;
int fb[maxn],s[1005],sg[1005];
void init()
{
fb[0]=1;
fb[1]=1;
for(int i=2;i<maxn;i++)
fb[i]=fb[i-1]+fb[i-2];
}
int get_sg(int x)
{
memset(sg,0,sizeof(sg));
for(int i=1;i<=x;i++)
{
memset(s,0,sizeof(s));
for(int j=1;j<maxn&&fb[j]<=i;j++)
s[sg[i-fb[j]]]=1;
for(int j=0;j<=i;j++)
{
if(s[j]==0)
{
sg[i]=j;
break;
}
}
}
return sg[x];
}
int main()
{
int m,n,p;
init();
while(scanf("%d%d%d",&m,&n,&p),m||n||p)
{
int a=get_sg(m);
int b=get_sg(n);
int c=get_sg(p);
if((a^b^c)==0)
printf("Nacci
");
else
printf("Fibo
");
}
return 0;
}
相关题目:
POJ 2234 Matches Game【nim博弈模板题】
HOJ 4388 Stone Game II
POJ 2975 Nim
HOJ 1367 A Stone Game
POJ 2505 A multiplication game
ZJU 3057 beans game
POJ 1067 取石子游戏
POJ 2484 A Funny Game
POJ 2425 A Chess Game
POJ 2960 S-Nim
POJ 1704 Georgia and Bob
POJ 1740 A New Stone Game
POJ 2068 Nim
POJ 3480 John
POJ 2348 Euclid's Game
HOJ 2645 WNim
POJ 3710 Christmas Game
POJ 3533 Light Switching Game
三.(green)博弈/树链博弈:
问题:
给定一棵有根树,(A) 和 (B)分别轮流删边,删边后不与根联通的子树也一并删去。
先考虑一个简单的模型:如果这棵树是一条链,那么就跟取石子一样;
再考虑一个复杂一点的,在根上再加一条链,那么,这就变成了取 (2) 堆石子的问题了。其(SG)值正是这 (2) 条链的异或,因此,我们可以将这 (2) 条链等效成长度为其(SG)值的异或值的链。
进而我们利用这个性质,将一个个分支简化成一条条链,这样,一棵树最终会被等效成一条链。
树链博弈
直接推结论的做法:题解
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1005;
vector<int>pic[N];
int depth[N],num[N],w[N],maxn;
void dfs(int v,int p,int d)
{
depth[v]=d;
if(w[v]==1)
num[d]++;
maxn=max(d,maxn);
for(int i=0;i<pic[v].size();i++)
{
int u=pic[v][i];
if(u==p)
continue;
dfs(u,v,d+1);
}
}
int main()
{
int n,u,v;
maxn=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
pic[u].pb(v);
pic[v].pb(u);
}
dfs(1,0,0);
int cnt=0;
for(int i=0;i<=maxn;i++)
{
if(num[i]&1)
cnt++;
}
if(cnt==0)
printf("Second
");
else
printf("First
");
return 0;
}
Gameia HDU - 6105
BZOJ2819 Nim 博弈论+树链剖分
参考博客