选钱博弈问题

来源:互联网 发布:周杰伦方文山知乎 编辑:程序博客网 时间:2024/05/29 14:07

下面的这道问题是某公司的校招题,近日听了程云老师的讲解,觉得恍然大悟。遂总结如下:

【题目】

给定一个整型数组money,代表数值不同的钱排成一条线。玩家A和玩家B依次拿走每张钱,规定玩家A先拿,玩家B后拿,但是每个玩家每次只能拿走最左或最右的钱,玩家A和玩家B都绝顶聪明。请返回最后获胜者的钱数。

【举例】

arr=[1,2,100,4]。
开始时玩家A只能拿走1或4。如果玩家A拿走1,则排列变为[2,100,4],接下来玩家B可以拿走2或4,然后继续轮到玩家A。如果开始时玩家A拿走4,则排列变为[1,2,100],接下来玩家B可以拿走1或100,然后继续轮到玩家A。玩家A作为绝顶聪明的人不会先拿4,因为拿4之后,玩家B将拿走100。所以玩家A会先拿1,让排列变为[2,100,4],接下来玩家B不管怎么选,100都会被玩家A拿走。玩家A会获胜,分数为101。所以返回101。
arr=[1,100,2]。
开始时玩家A不管拿1还是2,玩家B作为绝顶聪明的人,都会把100拿走。玩家B会获胜,分数为100。所以返回100。
==所以可以看到没有一定的方法保证先拿的钱数一定最多==

【思路】:

因为A、B都是绝顶聪明的,所以假设A先拿,他有两种方式即拿第一个或最后一个。但是不论他拿第一个还是最后一个之后,都会轮到B拿。这时的A就变成了后拿。
我们用firstGet(money[],i,j)表示先拿,lastGet(money[],i,j)表示后拿。

  • 如果A第一次拿了第一个,那么A下一次就会后拿剩下的,也就是lastGet(money[],i+1,j);
  • 如果A第一次拿了最后一个,那么A下一次也会后拿剩下的,也就是lastGet(money[],i,j-1);

因为A是聪明的,所以他会选择先拿第一个或最后一个使结果最大的。
同时B也是聪明的,他也会选择使结果对他有利的,也就是说A的lastGet()=小的firstGet()。
递归下去。终止的条件的条件为,最后只剩一张钱,那么就是getFirst拿走。
代码如下:

import java.util.*;public class Money{    public static void main(String [] args){        int money[]={2,3,5,9};        System.out.println(firstGet(money,0,money.length-1));    }    public static int firstGet(int[] money,int i,int j){        if(i==j){                //如果只剩一张钱,先拿的拿走            return money[i];        }else{               //先拿的判断是拿第一张好,还是最后一张好。            return Math.max(money[i]+lastGet(money,i+1,j),money[j]+lastGet(money,i,j-1));        }    }    public static int lastGet(int[] money,int i,int j){        if(i==j){            return 0;           }else{                //因为是后拿,大的已经被选走,所以就等于先拿下的。            return Math.min(firstGet(money,i+1,j),firstGet(money,i,j-1));        }    }}
0 0
原创粉丝点击