动态规划:游戏
游戏
www.acwing.com/problem/content/1390/


DP:
-
状态表示:
f[i][j]- 集合:先手对于区间 [ i , j ] [i,j] [i,j],选取的所有方案
- 属性:当前玩家相对于对手的最大得分差
-
状态计算: f [ i ] [ j ] = m a x ( w [ i ] − f [ i + 1 ] [ j ] , w [ j ] − f [ i ] [ j − 1 ] ) f[i][j]=max(w[i]-f[i+1][j],w[j]-f[i][j-1]) f[i][j]=max(w[i]−f[i+1][j],w[j]−f[i][j−1])
- 选左边: f [ i ] [ j ] = w [ i ] − f [ i + 1 ] [ j ] f[i][j]=w[i]-f[i+1][j] f[i][j]=w[i]−f[i+1][j]
- 选右边: f [ i ] [ j ] = w [ j ] − f [ i ] [ j − 1 ] f[i][j] = w[j]-f[i][j-1] f[i][j]=w[j]−f[i][j−1]
区间 DP:
- 枚举长度
- 枚举左起点
import java.util.*;
public class Main {
static final int N = 110;
static int[] w = new int[N];
static int[][] f = new int[N][N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int sum = 0;
for (int i = 0; i < n; i++) {
w[i] = sc.nextInt();
sum += w[i];
}
// 先枚举长度
for (int len = 1; len <= n; len++) {
// 再枚举起点
for (int i = 0; i + len - 1 < n; i++) {
int j = i + len - 1;
if (j == i) {
f[i][j] = w[i] - f[i + 1][j];
} else {
f[i][j] = Math.max(w[i] - f[i + 1][j], w[j] - f[i][j - 1]);
}
}
}
// A + B = sum; A - B = d
int d = f[0][n - 1];
System.out.printf("%d %d\n", (sum + d) / 2, (sum - d) / 2);
}
}
解析
为什么选用最大得分差?
- 如果当前玩家取走一个数,那么对手会在剩下的子数组中取数。(零和游戏)
- 当前得分差 = 当前玩家取走的数 - 对手在剩下子数组中的得分。
- 注意:这个得分差是相对的,当前玩家是交替的
当 i == j 时,dp[i][j] = nums[i],因为只有一个数,当前玩家只能取走它。
dp[0][0] = 4
dp[1][1] = 7
dp[2][2] = 2
dp[3][3] = 9
dp[4][4] = 5
dp[5][5] = 2
计算
dp[0][1]:
当前玩家可以选择 nums[0] 或 nums[1]。
- 如果取
nums[0],对手在nums[1..1] 中取数,得分差为4 - 7 = -3。 - 如果取
nums[1],对手在nums[0..0] 中取数,得分差为7 - 4 = 3。
当前玩家会选择最大值,因此dp[0][1] = 3。
计算
dp[1][2]:
当前玩家可以选择 nums[1] 或 nums[2]。
- 如果取
nums[1],对手在nums[2..2] 中取数,得分差为7 - 2 = 5。 - 如果取
nums[2],对手在nums[1..1] 中取数,得分差为2 - 7 = -5。
当前玩家会选择最大值,因此dp[1][2] = 5。
最终结果:
通过逐步填充 dp 表,最终得到 dp[0][5] = 7,表示玩家一比玩家二多得 7 分。
总和为 4 + 7 + 2 + 9 + 5 + 2 = 29,因此:
- 玩家一的得分为
(29 + 7) / 2 = 18。 - 玩家二的得分为
(29 - 7) / 2 = 11。
957

被折叠的 条评论
为什么被折叠?



