取球博弈
两个人玩取球的游戏。
一共有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
程序应该输出:
0 + 0 -
再例如,输入:
1 4 5
10 11 12 13 15
程序应该输出:
0 - 0 + +
再例如,输入:
2 3 5
7 8 9 10 11
程序应该输出:
0 0 0 0
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
思路:
题目的意思是定义了5局,每局总数不同,双方每次抽取的牌数不同,且每次抽取牌是在上一次的基础上(分解为子问题),因此可以用递归去解决
递归出口
//递归条件出结果
if(num<n[0]) {
if(myunum%2==1&&younum%2==0) {
return '+';
}
else if(myunum%2==0&&younum%2==1) {
return '-';
}
return '0';
}
递归体
注意点:
- 两人相互博弈,传入取球的数量后,还需交换参数,交换去取,且先进行加的参数为自己(由自己开始取)
boolean ping=false;
//for循环决定每次递归执行的多种方案
for(int i=0;i<3;i++) {
//判定第i层的参数变化,确定递归过程中参数的变化
if (num>=n[i]) {
char mid=judge(num-n[i], younum, myunum+n[i]);
//?过程中出现输赢才是关键,每一层的参数变化都不同,结果并不能决定输赢,每一种局面的结果都不相同,即递归的终点由于for循环的不同而不同
//而题目要求打平的情况为总能找到一种情况为平,故注意影响
//递归出口
if (mid=='-') {
return '+';
}
if (mid=='0') {,mn
//参数变化的过程中,出现平局即for循环遍历的情况下
ping=true;
}
}
}
- 递归回溯分析
判定输赢,递归回溯后的是三种方案的输赢结果,
其中回溯到第一层时
其中有一次赢(即对手数),则获胜,
若一次没赢,但有平数,则打平
若没出现平数,则输
package competion2016;
import java.util.Scanner;
public class 取球博弈 {
static int[] n=new int[3];
public static void main(String[] args) {
Scanner scanner =new Scanner(System.in);
for (int i = 0; i < 3; i++) {
n[i]=scanner.nextInt();
}
for (int i = 0; i < 5; i++) {
int num=scanner.nextInt();
//for循环决定每次递归执行的多种方案,递归深度决定判断的深度,递归出口决定判断的结果
char ans=judge(num,0,0);//
System.out.print(ans+" ");
}
System.out.println("");
}
private static char judge(int num,int myunum,int younum) {
//递归 的过程是先纵向再横向
// TODO 自动生成的方法存根
//递归条件出结果
if(num<n[0]) {
if(myunum%2==1&&younum%2==0) {
return '+';
}
else if(myunum%2==0&&younum%2==1) {
return '-';
}
return '0';
}
boolean ping=false;
//for循环决定每次递归执行的多种方案
for(int i=0;i<3;i++) {
//判定第i层的参数变化,确定递归过程中参数的变化
if (num>=n[i]) {
char mid=judge(num-n[i], younum, myunum+n[i]);
//?过程中出现输赢才是关键,每一层的参数变化都不同,结果并不能决定输赢,每一种局面的结果都不相同,即递归的终点由于for循环的不同而不同
//而题目要求打平的情况为总能找到一种情况为平,故注意影响
//递归出口
if (mid=='-') {//存在输,这3次方案结束
return '+';
}
if (mid=='0') {
//参数变化的过程中,出现平局即for循环遍历的情况下
ping=true;
}
}
}
//如果走到这一行,说明方案数全执行完,说明不存在对手输的情况
//递归体的返回值
if(ping) {
return '0';
}
return '-';
}
}