那么对于这些较难的博弈问题可以不断去找必败点,找出临界值SG
比如对于HDOJ 1729 Stone Game一题
http://acm.hdu.edu.cn/showproblem.php?pid=1729
我们可以设有一个箱子容量为s时,d是一个必败点
达到d这点的话,我们可以达到的点为 d+1 ~ d+d*d
所以一定是: d+d*d < s
为了找出临界值,于是我的设我一步走到d+1点
那么一定有: (d+1)*(d+1) + d+1 >= s
OK,话说到这里,我们由临界值得到了两个公式:
d + d*d < s --> d(d+1) < s
(d+1)*(d+1) + d+1 >= s --> (d+1)(d+2) >= s
那么我们由这两个公式
可以求出 s 的必败点 d
接下来要做的便是把d当作s去找它的必败点,直到找不下去
那么c呢 是起始的点数
我只要找到大于c的最小必败点
然后对每(d-c)异或,可以把
特例: c=s,c=0 是 必败点
AC CODE:
#include <iostream>
#include <cmath>
using namespace std;
int sg(int s, int c)
{
int t = (int)sqrt(double(s));
while (t*t+t >= s)
{
--t;
} // 找到符和条件的点
if (c > t) //找到大于c的最小必败点
return s - c;
else
return sg(t, c);
}
int main()
{
int i,j,k,n,m,t;
int s,c,d;
int cnt = 0;
while (scanf("%d",&n)!=EOF,n)
{
cnt++;
int ans = 0;
for (i=0;i<n;i++)
{
scanf("%d %d",&s,&c);
ans ^= sg(s,c);
}
if (!ans) printf("Case %d:/nNo/n",cnt);
else printf("Case %d:/nYes/n",cnt);
}
return 0;
}