题目:
两个人玩取球的游戏。
一共有 N 个球,每人轮流取球,每次可取集合 n1,n2,n3中的任何一个数目。
如果无法继续取球,则游戏结束。
此时,持有奇数个球的一方获胜。
如果两人都是奇数,则为平局。
假设双方都采用最聪明的取法,
第一个取球的人一定能赢吗?
试编程解决这个问题。
输入描述
输入格式:
第一行 3 个正整数n1,n2,n3 (0<n1,n2,n3<100),空格分开,表示每次可取的数目。
第二行 5 个正整数 x1,x2,⋯,x5 (0<xi<1000),空格分开,表示 5 局的初始球数。
输出描述
输出一行 5 个字符,空格分开。分别表示每局先取球的人能否获胜。
能获胜则输出 +,次之,如有办法逼平对手,输出 0,无论如何都会输,则输出 -。
输入输出样例
示例
输入
1 2 3
1 2 3 4 5
输出
+0 + 0 -
运行限制
最大运行时间:3s
最大运行内存: 256M
初始代码(会超时):
import java.util.Arrays; import java.util.Scanner; public class qu_qiu_bo_yi { static int[] N; public static void main(String[] args) { Scanner sc=new Scanner(System.in); N=new int[3]; int[] A=new int[5]; char[] result=new char[5]; for (int i=0;i<3;i++){ N[i]=sc.nextInt(); } Arrays.sort(N); for (int i=0;i<5;i++){ A[i]=sc.nextInt(); result[i]=f(A[i],0,0); } for (int i=0;i<5;i++){ System.out.print(result[i]+" "); } sc.close(); } public static char f(int num,int me,int you){ if (num<N[0]){ if ((me&1)==1&&(you&1)==0){ return '+'; } if ((me&1)==0&&(you&1)==1){ return '-'; } else { return '0'; } } boolean ping=false; for (int i = 0; i <3 ; i++) { if (num >= N[i]){ char result= f(num-N[i],you,me+N[i]); if (result=='-'){ return '+'; } if (result=='0'){ ping=true; } } } if (ping==true){ return '0'; } else { return '-'; } } }
|
首先解释一下位运算:
&运算符有两种用法:一种是为运算符;一种是逻辑运算符;
作为位运算符是进行二进制运算的,当两个对应位上都为1的时候才为1,否则为0
因为偶数二进制最后一位一定是0奇数最后一位一定是1,所以某个数n&1==1则n为奇数n&1==0则n为偶数。
比如2&1 相当于010&001结果为000=0为偶数
3&1相当于011&001结果为001=1为奇数。
我们再说一下为什么会超时:
因为xi最大为1000假设三个可取集合全为1,2,3则三个集合都可取三个集合取得的结果又有三种取法

如图会有3^n种结果。
就会造成超时,那么我们就要想办法改进,这里要用到“记忆递归”顾名思义就是在其中的某个结点记录下它走到最后的结果,那么当在后面结点中遇到同样的情况就不用再次递归了。
改进代码:
import java.util.Arrays; import java.util.Scanner; public class qu_qiu_bo_yi { static int[] N; public static void main(String[] args) { Scanner sc=new Scanner(System.in); N=new int[3]; int[] A=new int[5]; char[] result=new char[5]; for (int i=0;i<3;i++){ N[i]=sc.nextInt(); } Arrays.sort(N); for (int i=0;i<5;i++){ A[i]=sc.nextInt(); result[i]=f(A[i],0,0); } for (int i=0;i<5;i++){ System.out.print(result[i]+" "); } sc.close(); } private static char[][][] rem=new char[1000][2][2]; public static char f(int num,int me,int you){ if (num<N[0]){ if ((me&1)==1&&(you&1)==0){ return '+'; } if ((me&1)==0&&(you&1)==1){ return '-'; } else { return '0'; } } if (rem[num][me][you]!='\0'){ return rem[num][me][you]; } boolean ping=false; for (int i = 0; i <3 ; i++) { if (num >= N[i]){ char result= f(num-N[i],you,(N[i]&1)==0?me:1-me); if (result=='-'){ rem[num][me][you]='+'; return '+'; } if (result=='0'){ ping=true; } } } if (ping==true){ rem[num][me][you]='0'; return '0'; } else { rem[num][me][you]='-'; return '-'; } } }
|