这一类是最简单的入门级别啦,这些博弈问题的大前提来自优秀的学姐
求SG函数通常用dp||记忆化搜索
1、
POJ2975 Nim
题解:
这个题的题目描述就是我们跟踪代码会看到的过程
求Nim游戏获胜的方案,其实就是求第一步可以从哪些堆里拿。可以发现 SGi (第i堆石子)假如有k个,ta的后继状态可以转移到0~k-1,那么我们根据SG函数的定义可以知道SG[i]=a[i]
这里再提一点就是k^a[i]表示总的SG值去掉这一堆石子的SG值,我们为了让总的SG值为0,就要让这一堆也就是第i堆石子的SG值为k^a[i],要想让k^a[i]在取值范围内,【根据SG函数的求法mex】,只有当(k^a[i]) < a[i]时,k^a[i]是 SGi 的后继状态,在ta的取值范围内
剩下的下方普及向见咯!
代码:
#include <cstdio>
using namespace std;
int n,a[1005];
int main()
{
while (1)
{
scanf("%d",&n);if (!n) break;
int k=0,ans=0;
for (int i=1;i<=n;i++) scanf("%d",&a[i]),k^=a[i];
for (int i=1;i<=n;i++)
if ((k^a[i])<a[i]) ans++;
printf("%d\n",ans);
}
}
2、
POJ2960 S-Nim
题解:
似乎是ta怎么说你怎么做求一波SG函数就完结了?要时刻把握SG函数的性质式,这个题目描述写的特别好
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int rule[105],a[105],n,sg[10005],m;bool ext[10005];
void get_sg()
{
memset(sg,0,sizeof(sg));
for (int i=1;i<=10000;i++)
{
memset(ext,0,sizeof(ext));
for (int j=1;j<=n;j++)
if (i-rule[j]<0) break;
else ext[sg[i-rule[j]]]=1;
for (int j=0;;j++)
if (!ext[j]) {sg[i]=j;break;}
}
}
int main()
{
while (1)
{
scanf("%d",&n); if (!n) break;
for (int i=1;i<=n;i++) scanf("%d",&rule[i]);
sort(rule+1,rule+n+1);
get_sg();
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
int nn,k=0;scanf("%d",&nn);
for (int j=1;j<=nn;j++) scanf("%d",&a[i]),k^=sg[a[i]];
if (!k) printf("L");else printf("W");
}
printf("\n");
}
}
3、
POJ2425 A Chess Game
题解:
要用记忆化搜索求SG函数,注意SG函数是一个数字!一个状态的SG取决于ta的后继,后继所有SG的mex
代码:
#include <cstdio>
#include <cstring>
using namespace std;
int tot,nxt[499500],point[1005],v[499500],sg[1005];
void addline(int x,int y){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}
int get_sg(int x)
{
if (sg[x]!=-1) return sg[x];
bool ext[1005];memset(ext,0,sizeof(ext));
for (int i=point[x];i;i=nxt[i])
{
int t=get_sg(v[i]);
ext[t]=1;
}
for (int i=0;;i++)
if (!ext[i]){sg[x]=i;break;}
return sg[x];
}
int main()
{
int x,k,m,n;
while (~scanf("%d",&n))
{
memset(point,0,sizeof(point));tot=0;
memset(sg,-1,sizeof(sg));
for (int i=1;i<=n;i++)
{
scanf("%d",&k);
for (int j=1;j<=k;j++)
scanf("%d",&x),x++,addline(i,x);
}
while (scanf("%d",&m)&&m)
{
k=0;
for (int i=1;i<=m;i++)
{
scanf("%d",&x);x++;
k^=get_sg(x);
}
if (!k) printf("LOSE\n");else printf("WIN\n");
}
}
}