问题描述:
逗志芃又一次面临了危机。逗志芃的妹子是个聪明绝顶的人,相比之下逗志芃就很菜了。现在她妹子要和他玩一个游戏,这个游戏是这样的:一共有n个数(n是偶数)写成一行,然后两个人轮流取数,每次只能从最前面或者最后面取走一个数,全部取完则游戏结束,之后每个人取走的数的和就是每个人的得分。由于逗志芃妹子很厉害,但他又不想输,所以只能找到你了,你要告诉他最多可以得到多少分。(注意,妹子智商是maxlongint所以是不会犯错的,每次的策略必然最优,而且逗志芃是先手)
输入格式
第一行一个数n,表示有n个数。
第二行就是进行游戏的n个数。
输出格式
一个数,最高得分
样例输入
2
10 20
样例输出
20
数据规模和约定
例:0<n,m<=1000,每个数不超过10000 。
思路:
本题跟0-1背包很相似,0-1背包的每一次时取或者不取,而本题的每一次取最前面或者最后面的数字。逗志芃取的时候,选择能取得更多的情况,妹妹取的时候,会让他选择取得更少的情况。用step控制取的轮次,step为单数时,轮到逗志芃,为双数时,妹妹取。
完整代码:
import java.util.Scanner;
public class Main {
static int[] nums;
static int[][] res = new int[1000][1000]; // res[i][j]表示i到j区间能取到的最大值
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
sc.nextLine(); // 当第一行为数字,第二行为字符串时,要用sc.nextLine来消除回车带来的影响
String str = sc.nextLine(); // 获取第二行的字符
String[] temp = str.trim().split(" ");
nums = new int[n];
for (int i=0;i<n;i++){
nums[i] = Integer.parseInt(temp[i]);
}
System.out.println(solve(0,n-1,1));
}
/**
* @param start 前面的指针
* @param end 后面的指针
* @param step 表示进行到第几步了
* @return
*/
private static int solve(int start, int end, int step){
if (res[start][end]!=0) // 当res[i][j]存在时,直接返回 剪枝,避免超时
return res[start][end];
if (start==end) // 当只有一个数时,一定是妹妹取,返回0
return 0;
if (step%2==1){ // 步数为奇数时,逗志凡取,返回后面能取得较多的情况
return res[start][end] = Math.max((nums[start]+solve(start+1,end,step+1)),
nums[end]+solve(start,end-1,step+1));
}else { // 步数为偶数时,妹妹取,返回后面能取得较少的情况
return res[start][end] = Math.min(solve(start+1,end,step+1),
solve(start,end-1,step+1));
}
}
}