【递归到动态规划】:左右拿最大值问题

题目

在这里插入图片描述

思路

玩家都会有两个方法,就是先手拿牌和后手拿牌,先手拿牌的情况分两种拿左边的或者拿右边的,我们取二者中较大的,并且加上剩余牌后手拿的情况。然后分析后手拿的情况,后手拿一定是被动,而且对手已经选择了最好的情况,所以我们返回拿走牌剩余拿到较小的情况。最终的返回条件是只剩最后一张牌了。

代码

递归版

// 根据规则,返回获胜者的分数
public static int win1(int[] arr) {
    
    
	if (arr == null || arr.length == 0) {
    
    
		return 0;
	}
	int first = f1(arr, 0, arr.length - 1);
	int second = g1(arr, 0, arr.length - 1);
	return Math.max(first, second);
}

// arr[L..R],先手获得的最好分数返回
public static int f1(int[] arr, int L, int R) {
    
    
	if (L == R) {
    
    
		return arr[L];
	}
	int p1 = arr[L] + g1(arr, L + 1, R);
	int p2 = arr[R] + g1(arr, L, R - 1);
	return Math.max(p1, p2);
}

// // arr[L..R],后手获得的最好分数返回
public static int g1(int[] arr, int L, int R) {
    
    
	if (L == R) {
    
    
		return 0;
	}
	int p1 = f1(arr, L + 1, R); // 对手拿走了L位置的数
	int p2 = f1(arr, L, R - 1); // 对手拿走了R位置的数
	return Math.min(p1, p2);//对手留给你的肯定是最差的
}

动态规划版

public static int win3(int[] arr) {
    
    
	if (arr == null || arr.length == 0) {
    
    
		return 0;
	}
	int N = arr.length;
	int[][] f = new int[N][N];
	int[][] g = new int[N][N];
	for (int i = 0; i < N; i++) {
    
    
		f[i][i] = arr[i];//初始化对角线的值
	}
	for (int i = 1; i < N; i++) {
    
    
		int L = 0;
		int R = i;
		while (R < N) {
    
    
			f[L][R] = Math.max(arr[L] + g[L + 1][R], arr[R] + g[L][R - 1]);
			g[L][R] = Math.min(f[L + 1][R], f[L][R - 1]);
			L++;
			R++;
		}
	}
	return Math.max(f[0][N - 1], g[0][N - 1]);
}

猜你喜欢

转载自blog.csdn.net/VanGotoBilibili/article/details/115230220