题目: 题目链接
题目意思:
题目转换为熟悉的石子游戏就是,这里有m堆石子,每次可以把任意两堆合并,或者从某一堆中拿走一个,是不能操作
谁就输了。
由于总数不变,最终总是要一个个拿完。那么有机会获胜的一方,肯定是先要把所有的合在一起,那么最终就拼奇偶数
了。所以双方都要合并。
而且如果没有某堆只有一个的话,对方是阻挡不住的,没有取完,便被合并了。
所以就要考虑某堆只有一个的情况,单独考虑。
其中的操作包括:
1:把某堆只有一个的,取走
2:把两堆只有一个的,合并
3:把某堆只有一个的,合并给不是一个的
4:把不是一个的,取走一个
记忆化搜索
#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <functional>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cassert>
#include <bitset>
#include <stack>
#include <ctime>
#include <list>
#define INF 0x7fffffff
#define max3(a,b,c) (max(a,b)>c?max(a,b):c)
#define min3(a,b,c) (min(a,b)<c?min(a,b):c)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int t, n, index, sum, one;
int sg[55][60005];
int getsg(int i, int j)
{
if(sg[i][j] != -1)
return sg[i][j];
if(j == 1)
return sg[i][j] = getsg(i+1, 0);
sg[i][j] = 0;
//去掉一个的
if(i >= 1 && !getsg(i-1, j))
sg[i][j] = 1;
//去掉大于1的中的一个
else if(j >= 1 && !getsg(i, j-1))
sg[i][j] = 1;
//把1合并到非1
else if(i >= 1 && j>0 && !getsg(i-1, j+1))
sg[i][j] = 1;
//双1合并
else if(i >= 2 && ((j==0 && !getsg(i-2, j+2))|| (j && !getsg(i-2, j + 3))))
sg[i][j] = 1;
return sg[i][j];
}
int main()
{
scanf("%d", &t);
int cnt = 0;
mem(sg, -1);
while(t--)
{
cnt++;
scanf("%d", &n);
sum = 0;
one = 0;
for(int i = 0; i < n; ++i)
{
scanf("%d", &index);
if(index == 1)
one ++;
else
sum += (index + 1);
}
if(sum)
sum--;
printf("Case #%d: ", cnt);
if(getsg(one, sum))
printf("Alice\n");
else
printf("Bob\n");
}
return 0;
}

本文讨论了石子游戏中的策略选择,通过将问题转换为熟悉的游戏形式,分析了如何利用记忆化搜索来解决此类问题。文章详细介绍了记忆化搜索的实现过程,并提供了求解方法。

1776

被折叠的 条评论
为什么被折叠?



