问题描述
两个人玩取球的游戏。
一共有N个球,每人轮流取球,每次可取集合{n1,n2,n3}中的任何一个数目。
如果无法继续取球,则游戏结束。
此时,持有奇数个球的一方获胜。
如果两人都是奇数,则为平局。
假设双方都采用最聪明的取法,
第一个取球的人一定能赢吗?
试编程解决这个问题。
输入
第一行3个正整数n1 n2 n3,空格分开,表示每次可取的数目 (0<n1,n2,n3<100)
第二行5个正整数x1 x2 … x5,空格分开,表示5局的初始球数(0<xi<1000)
输出
一行5个字符,空格分开。分别表示每局先取球的人能否获胜。
能获胜则输出+,
次之,如有办法逼平对手,输出0,
无论如何都会输,则输出 -
输入例子 1
1 2 3
1 2 3 4 5
输出例子 1
+ 0 + 0 -
输入例子 2
1 4 5
10 11 12 13 15
输出例子 2
0 - 0 + +
输入例子 3
2 3 5
输出例子 3
7 8 9 10 11
+ 0 0 0 0
提示
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms
实现思路
深搜 + 记忆化, 每个人都是最优解 = 优先考虑赢的情况, 其次考虑平的情况, 再其次才是输。
实现代码
#include<iostream>
#include<algorithm>
using namespace std;
const int SIZE = 1e3 + 5;
int dp[SIZE][2][2];
int a[3];
int dfs(int now, int nowplayer, int otherplayer) {
if (dp[now][nowplayer][otherplayer]) {
return dp[now][nowplayer][otherplayer];
}
if (now < a[0]) {
if ((nowplayer & 1) == (otherplayer & 1)) return -1; //平
if (nowplayer & 1) return 1; //胜
return 2; //负
}
else {
bool noplayerwin = false;
for (int i = 2; i >= 0; i--) {
if (a[i] > now) continue;
else {
int otherresult = dfs(now - a[i], otherplayer, (nowplayer + a[i]) & 1);
if (otherresult == 2) return dp[now][nowplayer][otherplayer] = 1;
if (otherresult == -1) noplayerwin = true;
}
}
if (noplayerwin) return dp[now][nowplayer][otherplayer] = -1;
return dp[now][nowplayer][otherplayer] = 2;
}
}
int main() {
int maxnum;
memset(dp, 0, sizeof(dp));
cin >> a[0] >> a[1] >> a[2];
sort(a, a + 3);
for (int i = 1; i <= 5; i++) {
cin >> maxnum;
switch (dfs(maxnum, 0, 0))
{
case 1: cout << "+ "; break;
case 2: cout << "- "; break;
case -1: cout << "0 "; break;
}
}
return 0;
}