题目描述
两个人玩取球的游戏。一共有N个球,每人轮流取球,每次可取集合{n1,n2,n3}中的任何一个数目。
如果无法继续取球,则游戏结束。此时,持有奇数个球的一方获胜。如果两人都是奇数,则为平局。
假设双方都采用最聪明的取法,第一个取球的人一定能赢吗?试编程解决这个问题。
输入
输入存在多组测试样例,对于每一组测试数据:
第一行3个正整数n1 n2 n3,空格分开,表示每次可取的数目 (0<n1,n2,n3<100)
第二行5个正整数x1 x2 … x5,空格分开,表示5局的初始球数(0<xi<1000)
输出
一行5个字符,空格分开。分别表示每局先取球的人能否获胜。
能获胜则输出+,次之,如有办法逼平对手,输出0,无论如何都会输,则输出-
样例输入
1 2 3
1 2 3 4 5
1 4 5
10 11 12 13 15
2 3 5
7 8 9 10 11
样例输出
+0 + 0 -
0 - 0 + +
+0 0 0 0
【想说的】1.很容易被“每个人都采用最聪明的方法”给困惑住,实际上可以理解为每次都为自己找赢面,没找到就去找平局的情况,否则输掉。
2.为了减少时间复杂度,用dp记录每个局面的情况,主要记录轮到谁取球,A有多少,B有多少,注意:球数变动的时候dp要重新更新,不同的球数中dp的意义都不相同。
3.dfs递归去遍历所有情况
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n[4];//取球数组
int q[6];//5组球数
char r[6];//输出的符号
int dp[2][1003][1003];//dp【谁取】【先手多少球】【后手多少球】
// 1 先手胜 2 平局 3先手输
int dfs(int all,int x,int h,int w)
{
int sy=all-x-h;
if(dp[w][x][h])
{
return dp[w][x][h];
}
if(sy<n[0])
{
if(x%2==1&&h%2==0)
return dp[w][x][h]=1;
else if(x%2==0&&h%2==1)
return dp[w][x][h]=3;
return dp[w][x][h]=2;
}
if(w==1)//先手取球的时候
{
int p=0;//当没赢的时候看看会不会平局的记号
for(int i=2;i>=0;i--)//从多的开始取球
{
if(sy<n[i])
continue;
int res=dfs(all,x+n[i],h,0);
if(res==1)
return dp[w][x][h]=1;
if(res==2)
p=1;
}
if(p==1)
return dp[w][x][h]=2;
return dp[w][x][h]=3;
}
if(w==0)//后手取球的时候
{
int p=0;
for(int i=2;i>=0;i--)
{
if(sy<n[i])
continue;
int res=dfs(all,x,h+n[i],1);
if(res==3)
return dp[w][x][h]=3;
if(res==2)
p=1;
}
if(p==1)
return dp[w][x][h]=2;
return dp[w][x][h]=1;
}
}
int main()
{
while(~scanf("%d",&n[0]))
{
scanf("%d%d",&n[1],&n[2]);
sort(n,n+3);
for(int i=0;i<5;i++)
{
scanf("%d",&q[i]);
}
for(int i=0;i<5;i++)
{
memset(dp,0,sizeof(dp));
int tem=dfs(q[i],0,0,1);
if(tem==1)
r[i]='+';
else if(tem==2)
r[i]='0';
else if(tem==3)
r[i]='-';
}
for(int i=0;i<5;i++)
{
printf("%c ",r[i]);
}
printf("\n");
}
return 0;
}