蓝桥杯第七届真题 :取球博弈

点击查看:蓝桥杯历年真题 题解目录
取球博弈

在这里插入图片描述
在这里插入图片描述

下面有两段代码:
第一段代码: 思路清晰,未进行优化,只能得一部分分数
第二段代码: 在第一段代码的基础上采用记忆性递归,降低复杂度。
第一段代码的思路:
1. 利用递归求解
2. 递归出口,n<a[0]  即:石头数目小于可以取得的数目,停止递归
     当A方 为奇数,B方为 偶数时,  A方胜出。
     当B方 为奇数,A方为 偶数时,  B方胜出
     其余为平局。
3. 在 n>a[i]的条件下,执行递归
      如果存在递归返回 '-'   则A方获胜返回 '+'
      引入 平局变量  pingju: 默认为false;
      如果 有 "平局" 的情况  pingju = true;
      
      在不获胜,即仍能继续执行的情况下,判断是否存在平局
      if(存在平局) return '0' ;    else return '-';
package java_B_2016;
import java.util.Arrays;
import java.util.Scanner;
public class Main009_取球博弈2 {
   static int []a = new int[3];
   public static void main(String[] args) {
      Scanner in = new Scanner(System.in);
      for(int i=0;i<3;i++) {
         a[i]=in.nextInt();
      }
      Arrays.sort(a);
      for(int i=0;i<5;i++) {
         int n = in.nextInt();
         char res = f(n,0,0);
         System.out.print(res+" ");
      }
   }
   /**
    * @param n    球的总数目
    * @param me   我方持有的数目-->我方数目的奇偶性
    * @param you  对手持有的数目-->我方数目的奇偶性
    * @return
    */
   private static char f(int n, int me, int you) {
      if(n<a[0]) {  // n<a[0] 即双方没有了可取的情况,游戏结束 即递归出口
         if((me&1)==1 && (you&1)==0)  return '+';
         if((me&1)==0 && (you&1)==1)  return '-';
         else return '0';
      }
      boolean pingju = false;
      for(int i=0;i<3;i++) {
         if(n>=a[i]) {
            char res = f(n-a[i], you, me+a[i]);// 注意此处的 me 和 you交换了位置
            if(res=='-')
               return '+';
            if(res == '0')
               pingju=true;
         }
      }
      // 如果程序走到这一行,说明不存在对手输的情况,那么是否存在平局的情况
      if(pingju) return '0';
      else return '-';
   }
}
下段代码,是对上段代码的优化
记忆性递归:
package java_B_2016;
import java.util.Arrays;
import java.util.Scanner;
public class Main009_取球博弈3 {
   private static int[] n;
   public static void main(String[] args) {
       Scanner sc = new Scanner(System.in);
       n = new int[3];
       for(int i = 0; i < 3; i++) {
          n[i] = sc.nextInt();
       }
       Arrays.sort(n);//排序
       for (int i = 0; i < 5; i++) {
          int num = sc.nextInt();
          char res = f(num, 0, 0);
          System.out.print(res + " ");
       }
       System.out.println();
   }
   static char[][][]cache = new char[1000][2][2];
     /**
      * 参数代表着当前取球人面临的局面
      * @param num 球的总数
      * @param me 我方持有的数目-->我方数目的奇偶性
      * @param you 对手持有的数目-对方数目的奇偶性
      * @return
      */
   private static char f(int num, int me, int you) {
       if (num<n[0]){
         if ((me&1)==1&&(you&1)==0)return '+';
         else if ((me&1)==0&&(you&1)==1)return '-';
         else return '0';
       }
       if (cache[num][me][you]!='\0')return cache[num][me][you];
       boolean ping = false;
       for (int i = 0; i < 3; i++) {
          if (num >= n[i]) {
             char res = f(num - n[i], you, (n[i]&1)==0?me:(1-me));//注意此处,传递me和you的奇偶性
             if (res == '-')
              {
                cache[num][me][you]='+';
                return '+';
              }
              if (res == '0')
                 ping = true;
          }
       }
       //如果能走到第这行,说明不存在对手输的情况,那么是否存在平的情况
       if (ping){
         cache[num][me][you]='0';
         return '0';
       }else{
         cache[num][me][you]='-';
         return '-';
       }
   }
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值