1 class Solution {
2
3 public void printChoices(int[] A, int[][] C) {
4 System.out.println("硬币列表如下:");
5 for(int i=0,l=A.length; i<l; i++) {
6 System.out.print(A[i] + "\t");
7 }
8 System.out.println("");
9 final int N = C.length;
10 String[] names = {"本人", "对手"};
11 int L = 0, R = N-1, WHO = 0;
12 while(L<=R) {
13 int c = C[L][R];
14 System.out.println(names[WHO] + "选择第 " + c + " 个元素" + A[c]);
15 WHO = (WHO+1)%2;
16 if(L==c) {
17 L = L+1;
18 }
19 if(R==c) {
20 R = R-1;
21 }
22 if(L == R) {
23 break;
24 }
25 }
26 }
27
28 public int maxMoney(int[] A) {
29 final int N = A.length;
30 int[][] C = new int[N][N];
31 int[][] M = new int[N][N]; // 每个子问题最优解(赚的最多钱)
32
33 // 设M(i,j) 为从第i到第j个硬币中能获得的最大收入
34 // j-i>=2 时
35 // M(i,j) = max(
36 // A[i] + min(M(i+2,j), M(i+1,j-1)),
37 // A[j] + min(M(i+1,j-1), M(i,j-2)),
38 // );
39
40 // 初始化坐标 [i,i] 和 [i,i+1] 处的决策和最大收入
41 for(int i=0; i<N; i++) {
42 M[i][i] = A[i];
43 C[i][i] = i;
44 if(i<N - 1) {
45 M[i][i+1] = Integer.max(A[i], A[i+1]);
46 C[i][i+1] = (A[i] < A[i+1] ? i+1 : i);
47 }
48 }
49
50 // 计算所有 [i,i+2] [i,i+3]... 处的决策和最大收入
51 for(int i=N-2; i>=0; i--) {
52 for(int j=i+2; j<N; j++) {
53 int I = A[i] + Integer.min(M[i+2][j], M[i+1][j-1]);
54 int J = A[j] + Integer.min(M[i+1][j-1], M[i][j-2]);
55 M[i][j] = Integer.max(I, J);
56 C[i][j] = I>J ? i : j;
57 }
58 }
59
60 printChoices(A, C);
61 return M[0][N-1];
62 }
63
64 public static void main(String[] args) {
65 Solution s = new Solution();
66 int[] a = {1,20,10,2};
67 int r = s.maxMoney(a);
68 System.out.println(r);
69 }
70 }