取球博弈
两个人玩取球的游戏。
一共有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
首先声明,本人也是刚刚接触算法的菜鸟一枚,这篇文章紧紧是在学习之路上的笔记,不作为标准。
刚看到这道题也是没有头绪,然后参考各路大神解题思想,代码思路个人想法,未能优化。
思路:
1. 为保证手上的球数为奇数个,则奇数次取球时首要想法是取奇数个,可取集合中的奇数不符合剩余球数时取偶数个。偶数次取球时则首要想法取偶数个,可取集合中的偶数不符合剩余球数时取奇数个。
2. 保证手上为奇数的情况下,每次取球取满足要求的最大值,以压缩对手的可取空间。
import java.util.Scanner;
public class t9 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int[] a = new int[3];//可取集合
a[0] = in.nextInt();
a[1] = in.nextInt();
a[2] = in.nextInt();
int[] b = new int[5];//5局,每局初始球数
b[0] = in.nextInt();
b[1] = in.nextInt();
b[2] = in.nextInt();
b[3] = in.nextInt();
b[4] = in.nextInt();
for(int j = 0;j<b.length;j++){ //5局,循环5次
System.out.println("第"+j+"局");
int i = 1; //用作while循环标记
int m1 = 1; //表示1号选手第m1次取球,初始为1
int m2 = 1; //表示2号选手第m2次取球,初始为1
int sum1 = 0; //记录1号每次取球后的总球数
int sum2 = 0; //记录2号每次取球后的总球数
int k = b[j]; //K用于记录每次取球后剩余的球数,当前为初始化
while(k>=a[0]){ //只要剩余球数大于或等于每次可取球数的最低数,就循环。
if(i%2 == 1){ //如果为奇数,则表示1号选手取球,否则为2号选手
System.out.println(" 1号选手");
if(m1 % 2 == 1){ //判断1号选手是奇数次取球,是则首要先取奇数个球
System.out.println(" 1号选手第"+m1+"次");
boolean flag1 = false;
for(int x = a.length-1;x>=0;x--){ //从大到小遍历,取可选集合中的最大奇数个球
if(a[x]%2 == 1 && a[x]<=k){ //判断是否为奇数且小于或等于剩余球数
sum1 += a[x]; //总球数增加
System.out.println(" 1号取"+a[x]);
k = k-a[x]; //剩余球数减少
flag1 = true; //能取到奇数个球
break; //结束遍历
}
}
if(!flag1){ //如果不能取到奇数个球,则取偶数个球
for(int y = a.length-1;y>=0;y--){
if(a[y]%2 == 0 && a[y]<=k){
sum1 += a[y];
System.out.println(" 1号取"+a[y]);
k = k-a[y];
break;
}
}
}
}else{ //如果为第偶数次取球,则首要是取偶数个球,保证手上的球数为奇数
System.out.println(" 1号选手第"+m1+"次");
boolean flag1 = false;
for(int y = a.length-1;y>=0;y--){ //遍历可取集合的偶数,满足条件则本次取球结束
if(a[y]%2 == 0 && a[y]<=k){
sum1 += a[y];
System.out.println(" 1号取"+a[y]);
k = k-a[y];
flag1 = true;
break;
}
}
if(!flag1){ //如未能取偶数个球,则取奇数个球
for(int x = a.length-1;x>=0;x--){
if(a[x]%2 == 1 && a[x]<=k){
sum1 += a[x];
System.out.println(" 1号取"+a[x]);
k = k-a[x];
flag1 = true;
break;
}
}
}
}
m1++; //1号选手第m1次取球加一
}else{ //2号选手类推
System.out.println(" 2号选手");
if(m2 % 2 == 1){
System.out.println(" 2号选手第"+m2+"次");
boolean flag1 = false;
for(int x = a.length-1;x>=0;x--){
if(a[x]%2 == 1 && a[x]<=k){
sum2 += a[x];
System.out.println(" 2号取"+a[x]);
k = k-a[x];
flag1 = true;
break;
}
}
if(!flag1){
for(int y = a.length-1;y>=0;y--){
if(a[y]%2 == 0 && a[y]<=k){
sum2 += a[y];
System.out.println(" 2号取"+a[y]);
k = k-a[y];
break;
}
}
}
}else{
System.out.println(" 2号选手第"+m2+"次");
boolean flag1 = false;
for(int y = a.length-1;y>=0;y--){
if(a[y]%2 == 0 && a[y]<=k){
sum2 += a[y];
System.out.println(" 2号取"+a[y]);
k = k-a[y];
flag1 = true;
break;
}
}
if(!flag1){
for(int x = a.length-1;x>=0;x--){
if(a[x]%2 == 1 && a[x]<=k){
sum2 += a[x];
System.out.println(" 2号取"+a[x]);
k = k-a[x];
flag1 = true;
break;
}
}
}
}
m2++;
}
i++; //循环标记
}//while
System.out.println("sum1="+sum1+" sum2="+sum2);
if(sum1%2==1 && sum2%2==0){
System.out.println("+");
}else if(sum1%2==0 && sum2%2==1){
System.out.println("-");
}else{
System.out.println("0");
}
}//for
}//main
}//class
输出格式并未符合题目输出要求,打印内容紧紧是为了了解程序思路。