【BZOJ 1874:[BeiJing2009 WinterCamp]取石子游戏 】题解
题目链接
题目
小H和小Z正在玩一个取石子游戏。 取石子游戏的规则是这样的,每个人每次可以从一堆石子中取出若干个石子,每次取石子的个数有限制,谁不能取石子时就会输掉游戏。 小H先进行操作,他想问你他是否有必胜策略,如果有,第一步如何取石子。
思路
博弈论,考虑把题目变成Nim游戏。
把 \([0, 1000]\) 按可行操作变成一个有向图,然后处理出它们的SG函数。
然后,把原先的每堆石子通过SG函数转化为真正的石子,然后跑一遍Nim即可。
Code
#include<bits/stdc++.h>
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define N 1010
int n, m, i, j, k, T;
int a[N], b[N], c[N], t[N], x[N], ans;
signed main()
{
n=read();
for(i=1; i<=n; ++i) a[i]=read();
m=read();
for(i=1; i<=m; ++i) b[i]=read();
for(i=1; i<=1000; ++i)
{
for(j=1; j<=m && b[j]<=i; ++j)
t[c[i-b[j]]]=i;
for(j=0; j<=1000; ++j)
if(t[j]!=i) break;
c[i]=j;
}
for(i=1; i<=n; ++i) x[i]=c[a[i]];
for(i=1; i<=n; ++i) ans^=x[i];
printf(ans ? "YES\n" : "NO\n");
if(ans)
{
for(i=1; i<=n; ++i)
for(j=1; j<=m && b[j]<=a[i]; ++j)
if(c[a[i]-b[j]]==(ans^x[i]))
return printf("%d %d", i, b[j]), 0;
}
return 0;
}
总结
对于这类常见的非经典Nim游戏问题,可以通过有向图预处理SG函数,转化为Nim游戏。
这种做法在简单博弈论中很常见。
本文来自博客园,作者:zhangtingxi,转载请注明原文链接:https://www.cnblogs.com/zhangtingxi/p/16013639.html