这是一篇没有看完的博客
“
I
m
p
a
r
t
i
a
l
C
o
m
b
i
n
a
t
o
r
i
a
l
G
a
m
e
s
”
(
以
下
简
称
I
C
G
)
。
“Impartial Combinatorial Games”(以下简称ICG)。
“ImpartialCombinatorialGames”(以下简称ICG)。
满足以下条件的游戏是
I
C
G
ICG
ICG:
1、有两名选手;
2、两名选手交替对游戏进行移动(
m
o
v
e
move
move),每次一步,选手可以在(一般而言)有限的合法移动集合中任选一种进行移动;
3、对于游戏的任何一种可能的局面,合法的移动集合只取决于这个局面本身,不取决于轮到哪名选手操作、以前的任何操作、骰子的点数或者其它什么因素; 4、如果轮到某名选手移动,且这个局面的合法的移动集合为空(也就是说此时无法进行移动),则这名选手负。
根据这个定义,很多日常的游戏并非
I
C
G
ICG
ICG。例如象棋就不满足条件3,因为红方只能移动红子,黑方只能移动黑子,合法的移动集合取决于轮到哪名选手操作。
定
义
P
−
p
o
s
i
t
i
o
n
和
N
−
p
o
s
i
t
i
o
n
定义P-position和N-position
定义P−position和N−position:
其中
P
P
P代表
P
r
e
v
i
o
u
s
Previous
Previous,
N
N
N代表
N
e
x
t
Next
Next,直观的说,上一次
m
o
v
e
move
move的人有必胜策略的局面是
P
−
p
o
s
i
t
i
o
n
P-position
P−position,也就是“后手可保证必胜”或者“先手必败”,现在轮到
m
o
v
e
move
move的人有必胜策略的局面是
N
−
p
o
s
i
t
i
o
n
N-position
N−position,也就是“先手可保证必胜”。
更严谨的定义是:
1.无法进行任何移动的局面(也就是
t
e
r
m
i
n
a
l
p
o
s
i
t
i
o
n
terminal position
terminalposition)是
P
−
p
o
s
i
t
i
o
n
P-position
P−position;
2.可以移动到
P
−
p
o
s
i
t
i
o
n
P-position
P−position的局面是
N
−
p
o
s
i
t
i
o
n
N-position
N−position;3.所有移动都导致
N
−
p
o
s
i
t
i
o
n
N-position
N−position的局面是
P
−
p
o
s
i
t
i
o
n
P-position
P−position。
法一:SG打表找规律
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
///打表
///f[]:可以取走的石子个数
///sg[]:0~n的SG函数值
///hash[]:mex{}
int f[N],sg[N],hash[N];
void getSG(int n,int m)
{
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<=m;j++)
hash[sg[i-f[j]]]=1;
for(j=0;j<=n;j++) //求mes{}中未出现的最小的非负整数
{
if(hash[j]==0)
{
sg[i]=j;
break;
}
}
}
}
///如果有多堆,则
/// num=sg[n1]^sg[n2]^sg[n3]^....^sg[nx];
/// if(num==0) 则先手必败
int main()
{
int n,k,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>f[i];
}
getSG(n,m);
for(int i=0;i<=n;++i) printf("%d %d\n",i,sg[i]);
}
法二: d f s dfs dfs版打表
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
///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=1;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;
}
///如果有多堆,则
/// num=sg[n1]^sg[n2]^sg[n3]^....^sg[nx];
/// if(num==0) 则先手必败
int main()
{
int k,m;
cin>>m>>n;
memset(sg,-1,sizeof(sg));
for(int i=1;i<=n;i++)
{
cin>>s[i];
}
SG_dfs(m);
for(int i=0;i<=m;++i) printf("%d %d\n",i,sg[i]);
}
K M P 算 法 : KMP算法: KMP算法:KMP算法模板