题目
A、B两伙马贼意外地在一片沙漠中发现了一处金矿,双方都想独占金矿,但各自的实力都不足以吞下对方,经过谈判后,双方同意用一个公平的方式来处理这片金矿。处理的规则如下:他们把整个金矿分成n段,由A、B开始轮流从最左端或最右端占据一段,直到分完为止。
马贼A想提前知道他们能分到多少金子,因此请你帮忙计算他们最后各自拥有多少金子?(两伙马贼均会采取对己方有利的策略)
输入
测试数据包含多组输入数据。输入数据的第一行为一个正整数T(T<=20),表示测试数据的组数。然后是T组测试数据,每组测试数据的第一行包含一个整数n,下一行包含n个数(n <= 500 ),表示每段金矿的含金量,保证其数值大小不超过1000。
输出
对于每一组测试数据,输出一行"Case #id: sc1 sc2",表示第id组数据时马贼A分到金子数量为sc1,马贼B分到金子数量为sc2。详见样例。
样例输入
2
6
4 7 2 9 5 2
10
140 649 340 982 105 86 56 610 340 879
样例输出
Case #1: 18 11
Case #2: 3206 981
思路
参考博客:传送门
分析可知采用动态规划的思想,每次拿取从整体考虑,且存在最优子结构
令a?表示序列中的第一个或最后一个值、f[i][j]表示从第i个到第j个拿取的最大金子数、sum[i][j]表示从第i个到第j个金子总和
如果先手拿走ai(第一个),那么先手最大的金子数即为
f[i][j] = i + (sum[i+1][j] - f[i+1][j]) 即 f[i][j] = sum[i][j] - f[i+1][j]
如果先手拿走aj(最后一个),那么先手最大的金子数即为
f[i][j] = aj + (sum[i][j-1] - f[i][j-1]) 即 f[i][j] = sum[i][j] - f[i][j-1]
总结为:f[i][j] = sum[i][j] - min(f[i+1][j], f[i][j-1])
其中sum数组可以简化为一维差运算得到,代码中的arr即为f数组
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
int u = 0;
while(u < t){
u ++;
//f(i, j) = sum(i, j) - min{f(i + 1, j), f(i, j - 1)}
int n = cin.nextInt();
int[] sum = new int[505];
int[][] arr = new int[505][505];
for(int i=1; i<=n; i++){
arr[i][i] = cin.nextInt();
sum[i] = sum[i-1] + arr[i][i];
}
for(int i=n; i>=1; i--){
for(int j=i+1; j<=n; j++){
arr[i][j] = (sum[j] - sum[i-1]) - Math.min(arr[i+1][j], arr[i][j-1]);
}
}
System.out.printf("Case #"+u+": "+arr[1][n]+" "+(sum[n] - arr[1][n])+"\n");
}
cin.close();
}
}
如有错误或不合理的地方,敬请指正~
加油!!