题目:点击打开链接
有两个队伍,队员交叉坐,轮流从一堆石子中取石子,每个人都规定了去石子的最大数量,取到最后一个石子的人所属的队伍输。问第一个队伍是否会赢。
通过求sg函数来判断,sg[i][j]表示当第i个人取是还有j个石子的情况。先初始化,无论是谁,是要面对1个石子的情况,那么肯定输,所以sg[i][1] = 0(或者谁面对石子数是0的情况谁就赢即 sg[i][0] = 1)。最终我们要判断的是sg[1][sum]的值,也就从此递归,有一个地方我一开始没有考虑到的就是递归的人数如果大于所有的人数,那么就要回到第一个队员开始再一轮的取石子,所以getsg函数中第一二两句就是这个作用……剩下的就是求SG函数的过程了。看其他人写的,这种方法貌似也是动态规划。
#include <stdio.h>
#include <string.h>
int s;
int a[25];
int sg[25][9000];//sg[i][j]表示第i个人拿的时候还剩下j个石子
int getsg(int m, int n)
{
if(m > s * 2)//开始一直没加这个条件,当一轮取完之后,石子还没有被取尽,那么就要继续从第一个开始循环
return getsg(m - s * 2, n);
if(sg[m][n] != -1)
return sg[m][n];
int i;
bool hash[110];
memset(hash, 0, sizeof(hash));
for(i = 1; i <= a[m] && n - i > 0; i++)
hash[getsg(m + 1, n - i)] = 1;
for(i = 0; i < 100; i++)
if(hash[i] == 0)
break;
return sg[m][n] = i;
}
int main (void)
{
while(scanf("%d", &s) != EOF)
{
if(s == 0)
break;
int sum, i;
scanf("%d", &sum);
for(i = 1; i <= 2 * s; i++)
scanf("%d", &a[i]);
memset(sg, -1, sizeof(sg));
for(i = 0; i <= s * 2; i++)
{
sg[i][1] = 0;//轮到某个人取但只剩下1个那么必输
}
int ok = getsg(1, sum);
if(ok == 0)
printf("0\n");
else
printf("1\n");
}
return 0;
}