这道题是一道比较绕的题,但只要把其中的逻辑关系搞明白了,问题就能迎刃而解,有两个注意点:
- 调用递归,递归函数的好坏决定着算法成功与否(逻辑复杂)
- 动态规划,空间换时间使得代码性能提升(不用动态规划只能通过数据量较小的30%的数据,也就是只能拿到30%的分数)
取球博弈:
两个人玩取球的游戏。
一共有N个球,每人轮流取球,每次可取集合{n1,n2,n3}中的任何一个数目。
如果无法继续取球,则游戏结束。
此时,持有奇数个球的一方获胜。
如果两人都是奇数,则为平局。
假设双方都采用最聪明的取法,
第一个取球的人一定能赢吗?
试编程解决这个问题。
输入格式:
第一行3个正整数n1 n2 n3,空格分开,表示每次可取的数目 (0<n1,n2,n3<100)
第二行5个正整数x1 x2 … x5,空格分开,表示5局的初始球数(0<xi<1000)
输出格式:
一行5个字符,空格分开。分别表示每局先取球的人能否获胜。
能获胜则输出+,
次之,如有办法逼平对手,输出0,
无论如何都会输,则输出-
static int[] a=new int[3];
static char[][][] cache=new char[1000][2][2];//1奇0偶
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
for(int i = 0;i<3;i++) {
a[i]=reader.nextInt();
}
Arrays.sort(a);
for(int i=0;i<5;i++) {
System.out.print(test(reader.nextInt(),0,0)+" ");
}
}
private static char test(int n, int me, int you) {
if(n<a[0]) {
if(me==1&&you==0)return '+';
else if(me==0&&you==1) return '-';
else return '0';
}
if(cache[n][me][you]!='\0')return cache[n][me][you];
boolean res=false;
for(int i=0;i<a.length;i++) {
if(n<a[i])break;
if(test(n-a[i],you,(me+a[i])&1)=='-') {
cache[n][me][you]='+';
return '+';
}
else if(test(n-a[i],you,(me+a[i])&1)=='0')res=true;
}
if(res) {cache[n][me][you]='0';return '0';}
else {cache[n][me][you]='-';return '-';}
}
首先是对题目的理解,对于任何选择,只要有一种能制胜,那就return ‘+’
如果不存在这种情况就看有没有逼平的局面,有->return ‘0’
else return ‘-’
然后是递归函数的理解,一开始是我选,结果如何取决于你选的结果。轮到你选的时候也调用同一个递归函数,所以又会回到我选,直到可以跳出函数,就可以知道结果。很多递归函数都是这样写,给一个动力,使其能够以函数的出口为方向。
如果有时间,可以考虑动态规划法。当表中有数据时,可以查表。