先后抽纸牌游戏 暴力递归

题目描述

给定一个整形数组arr,代表数值不同的纸牌排成一条线
玩家A和玩家B一次拿走每张纸牌
规定玩家A先拿,玩家B后拿
但是每个玩家每次只能只能拿走最左或者最右的纸牌
双方玩家都会使得对方在改变策略的情况下,对方不会获得更大收益
请问最后获胜者的分数?

思路分析:

同一个轮次,面对同样的L R, 先手必然会选较大的值,后首面对的也是同样的L R,但因为是先手选完之后才选择,所以 只能选其中较小的值

详解:

定义两个函数: F( arr, L, R),表示在[L,R]上,先手选择可以获得的最大分数。S( arr, L, R),表示在[L,R]上,后手选择可以获得的最大分数


先手F( arr, L, R)函数:

base case: 当只有一张牌(L==R),只能选择该张牌

选L:如果选择的是 L位置上的牌,那么接下来会选 [L+1,R]后手选择可以获得的最大分数,即 S(arr,L+1,R),此时最大得分是 arr[L]+S(arr,L+1,R);

选R:如果选择的是 R位置上的牌,那么接下来会选 [L,R-1]后手选择可以获得的最大分数,即 S(arr,L,R-1),此时最大得分是 arr[R]+S(arr,L,R-1);

决策:最后选择以上两种情况的较大值,作为自己的分数


后手S(arr,L,R)函数:

base case: 当只有一张牌(L==R),由于是后手选择,当对手把该张牌选走,就没有牌,即 得分为0

如果对手先手挑走了L:此时就相当于我们在[L+1,R]上 先手选择可以获得的最大分数,即F( arr, L+1, R)

如果对手先手挑走了R:此时就相当于我们在[L,R-1]上 先手选择可以获得的最大分数,即F( arr, L, R-1)

决策:由于是 后手选牌,自己 没有决定权对手一定会按照对自己最坏的情况进行选择,即 我们只能是上面两种情况的较小值,作为自己的分数

可以大致看一下下面这个简单的实例:

在开始看具体代码前,我们 必须要十分明确F(arr,L,R)方法和S(arr,L,R)方法的定义,这一点很重要!!!

F( arr, L, R),表示在[L,R]上,先手选择可以获得的最大分数
S( arr, L, R),表示在[L,R]上,后手选择可以获得的最大分数

在设计F( arr, L, R)时,会有 S( arr, L, R)的涉及,我们可以把他当做一个 黑盒,只需要明白他的作用,后面再写出他的方法体!

具体代码

//这是主方法,我们先看下面的f方法和s方法,再回来看win方法
 public static int win(int[] arr) {

    //输入的无效数组
     if (arr==null || arr.length==0) {
         return 0;
     }

    //返回先手和后手选择中较大的分数
     return Math.max(
             f(arr, 0, arr.length-1), 
             s(arr, 0, arr.length-1)
     );
 }
 ​
 //先手选择,在L~R上获得的最大分数
 public static int f(int[] arr, intL, intR) {

    //如果只剩一张牌,那么只能选这张牌
     if (L==R) {
         return arr[L];
     }
 ​
    //从选左和选右中的较大值
     return Math.max(
             arr[L] +s(arr, L+1, R), 
             arr[R] +s(arr, L, R-1)
     );
 }
 ​
 //后手选择,在L~R上获得的最大分数
 public static int s(int[] arr, intL, intR) {

    //如果只剩一张牌,由于是后手,所以没得选
     if (L==R) {
         return 0;
     }

 ​    //当对方选完,变成你先手时,你只能选择对方留给你的较小值
     return Math.min(
         f(arr, L+1, R), 
         f(arr, L, R-1)
     );
 }

第一次写,写的不好或者有其他意见,你的都是对的

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值