P39-预测赢家-递归

//预测赢家
/*
 * 给定一个表示分数的非负整数数组。玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端拿取分数,
 * 然后玩家1拿,......。每次一个玩家只能拿取一个分数,分数被拿取之后不再可取。直到没有剩余分数可取时游戏结束。
 * 最终获得分数总和最多的玩家获胜
 * 给定一个表示分数的数组,预测玩家1是否会成为赢家。你可以假设每个玩家的玩法都会使他的分数最大化。
 *
 * 扩展:石子游戏
 * */
public class P39 {
    public static void main(String[] args) {

        int[] arr = new int[]{5,200,2,3,5};
//        int[] arr = new int[]{5,200,2,3};
        int sum = 0;    //数组总分
        for(int i: arr){
            sum += i;
        }

        int p1 = maxScore(arr, 0, arr.length-1);        //p1先手,预测能否成为赢家,一直递归下去假设是取左边还是取右边,直到得到最大值
        int p2 = sum - p1;
        System.out.println(p1 > p2);
    }

    //递归
    //递归出口 只有一个元素或两个元素,返回最大的值,之后的都是通过max来判断
    //p1 max(fun(l), fun(r))
    //p2 max(fun(l), fun(r))
    //max(p1, p2)

    //l是左指针,r是右指针
    /*
    * 公式计算
    * 假设p1取l,p2剩下l+1和r可以取,
    *       假设p2取l+1,p1剩下l+2和r可以取
    *       假设p2取r,p1剩下l+1和r-1可以取
    *           之后p2怎么取,都是这两个公式 {l+2和r}、{l+1和r-1} (前提是l和r要重新指向)
    *           但p2是聪明的,假设{l+2和r}能让p1更大时,p2就会取r,导致你只能在{l+1和r-1}中取,让你处于不利状态
    * 假设p1取r,p2剩下l和r-1可以取
    *       假设p2取l,p1剩下l+1和r-1可以取
    *       假设p2取r-1,p1剩下l和r-2可以取
    *           之后p2怎么取,都是这两个公式 {l+1和r-1}、{l和r-2} (前提是l和r要重新指向)
    *
    * */
    public static int maxScore(int[] arr, int l, int r) {
        if (l == r) {       //如果只剩一个元素,只能选择它了
            return arr[l];
        }

        if (r - l == 1) {       //如果还剩两个元素,当然是挑选大的
            return Math.max(arr[l], arr[r]);
        }

        int left = 0;
        int right = 0;
        if (r - l > 1) {        //有两个以上的元素时
            //因为对手是聪明的,只会让你处于不利,不会让你取较大值,会抢走了较大值,所以你只剩下较小值可取,即Math.min
//            left = arr[l] + Math.min(maxScore(arr, l + 2, r), maxScore(arr, l + 1, r - 1));     //如果是取左边的元素,统计最高能获多少分
//            right = arr[r] + Math.min(maxScore(arr, l + 1, r - 1), maxScore(arr, l, r - 2));    //如果是取右边的元素,统计最高能获多少分

            //看到有重复计算的问题,maxScore(arr, l + 1, r - 1)重复递归了,需要优化
            int num = maxScore(arr, l + 1, r - 1);
            left = arr[l] + Math.min(maxScore(arr, l + 2, r), num);
            right = arr[r] + Math.min(num, maxScore(arr, l, r - 2));
        }

        return Math.max(left, right);
    }

    //仍然有太对递归,需要优化
}

 

posted @ 2022-04-11 14:21  YonchanLew  阅读(44)  评论(0)    收藏  举报