蓝桥杯-取球博弈

取球博弈

两个人玩取球的游戏。
一共有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,否则按无效代码处理。

import java.util.*;
public class Main{
	
	private static int[] n = new int[3];
	private static int N;
	private static char[][][] cache = new char[1000][3][3];
	public static char f(int N,int me,int you){
	    if(cache[N][me][you]!='\0')
	    return cache[N][me][you];
		
		if(N<n[0]){
			if((me&1)==1&&(you&1)==0){
				return cache[N][me][you]='+';
			}else if((me&1)==0&&(you&1)==1){
				return cache[N][me][you]='-';
				
			}else {
				return cache[N][me][you]='0';
			}
		}
		boolean flag = false;
		for(int i=0;i<3;i++){
			if(N>=n[i]){
			char cc = f(N-n[i],you,(n[i]&1)==1?(1-me):me);
			if(cc=='-')
				return cache[N][me][you]='+';
			else if(cc=='0'){
				flag = true;
			}
		}
	}
		if(flag==true){
			return cache[N][me][you]='0';
		}else{
			return cache[N][me][you]='-';
		}
}
	public static void main(String[] args){
		Scanner scanner = new Scanner(System.in);
		for(int i=0;i<3;i++){
			n[i]=scanner.nextInt();
		}
		Arrays.sort(n);
		for(int i=0;i<5;i++){
			N=scanner.nextInt();
			char c=f(N,0,0);
			System.out.printf("%c ",c);
		}
		System.out.printf("\n");
		
	}
}

笔记:
1.博弈题,当前局面,由递归子局面决定,子局面存在输的情况,当前最优局面必胜;如果子局面不存在输的情况,那么如果存在平局,那么当前局面最优平局,否则,当前局面输。
2.递归子局面时,我和对手互换,f(n-n[i],you,me+n[i])
3.由于本题只需要考虑局面奇偶性,无需考虑具体个数,所以直接用0,1作为偶数和奇数参数进行变换,偶+任意一个数,此数奇偶性不变(me),奇+任意一个数,此书奇偶性改变(1-me)。
4.用cache作为记忆化缓存每次记录过的结果,如果没有记录过,那么cache为初始值,cache定义为 char[] ,char数组初始值都为’\0’。
5.这题该bug改了半天,发现:
第一,当最后双方都是偶数的时候也是平局,题意没说清楚,我没有考虑这种情况。
第二,记忆化cache套路就是,首先在dfs内部一开始先判断cache是否记录过,若已经记录过则直接返回cache存的值,然后在每个return返回值的地方在返回之前先保存到cache里再返回,则完成记忆化。
第三,每次dfs取球之前都要判断先目前所剩余的N是否还够拿,如果N>=n[i]才可以拿,最后递归边界条件就是剩余球已经不够拿了,即N<取球数最小值,所以一开始要对取球数目先排序取得第一个最小数目。
7.最后,java的变量一般设置为private static,方法一般设置为public static,当然图省事,直接都只设置为static也行。
(debug真的需要用脑子一点一点的排查异常的情况,一点一点的测试出来不对的地方,然后逐渐定位。。。。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值