[1,2,100,8]纸牌游戏,有A、B两个玩家,先手后手都是只能从左边,右边拿。谁分多胜。
    范围上尝试,F(arr,L,R) L~R中拿到最大分数 。

    1. // 暴力递归
    2. public static int win1(int[] arr) {
    3. if (arr == null || arr.length == 0) {
    4. return 0;
    5. }
    6. int first = f1(arr, 0, arr.length - 1);
    7. int second = g1(arr, 0, arr.length - 1);
    8. return Math.max(first, second);
    9. }
    10. // arr[L..R],先手获得的最好分数返回,
    11. public static int f1(int[] arr, int L, int R) {
    12. if (L == R) {
    13. return arr[L]; // 一张牌
    14. }
    15. int p1 = arr[L] + g1(arr, L + 1, R);
    16. int p2 = arr[R] + g1(arr, L, R - 1);
    17. return Math.max(p1, p2);
    18. }
    19. // // arr[L..R],后手获得的最好分数返回
    20. public static int g1(int[] arr, int L, int R) {
    21. if (L == R) { // 最后一张牌肯定是先手的
    22. return 0;
    23. }
    24. int p1 = f1(arr, L + 1, R); // 对手拿走了L位置的数
    25. int p2 = f1(arr, L, R - 1); // 对手拿走了R位置的数
    26. return Math.min(p1, p2);
    27. }
    28. // 记忆化搜索,搞定可变参数组合
    29. public static int win2(int[] arr) {
    30. if (arr == null || arr.length == 0) {
    31. return 0;
    32. }
    33. int N = arr.length;
    34. //范围函数L不可能大于R,意味着下半区没有用
    35. int[][] fmap = new int[N][N];
    36. int[][] gmap = new int[N][N];
    37. for (int i = 0; i < N; i++) {
    38. for (int j = 0; j < N; j++) {
    39. fmap[i][j] = -1;
    40. gmap[i][j] = -1;
    41. }
    42. }
    43. int first = f2(arr, 0, arr.length - 1, fmap, gmap);
    44. int second = g2(arr, 0, arr.length - 1, fmap, gmap);
    45. return Math.max(first, second);
    46. }
    47. public static int f2(int[] arr, int L, int R, int[][] fmap, int[][] gmap) {
    48. if (fmap[L][R] != -1) {
    49. return fmap[L][R];
    50. }
    51. int ans = 0;
    52. if (L == R) {
    53. ans = arr[L];
    54. } else {
    55. int p1 = arr[L] + g2(arr, L + 1, R, fmap, gmap);
    56. int p2 = arr[R] + g2(arr, L, R - 1, fmap, gmap);
    57. ans = Math.max(p1, p2);
    58. }
    59. fmap[L][R] = ans;
    60. return ans;
    61. }
    62. // arr[L..R],后手获得的最好分数返回
    63. public static int g2(int[] arr, int L, int R, int[][] fmap, int[][] gmap) {
    64. if (gmap[L][R] != -1) {
    65. return gmap[L][R];
    66. }
    67. int ans = 0;
    68. if (L != R) {
    69. int p1 = f2(arr, L + 1, R, fmap, gmap); // 对手拿走了L位置的数
    70. int p2 = f2(arr, L, R - 1, fmap, gmap); // 对手拿走了R位置的数
    71. ans = Math.min(p1, p2);
    72. }
    73. gmap[L][R] = ans;
    74. return ans;
    75. }
    76. // 动态规划
    77. public static int win3(int[] arr) {
    78. if (arr == null || arr.length == 0) {
    79. return 0;
    80. }
    81. int N = arr.length;
    82. int[][] fmap = new int[N][N];
    83. int[][] gmap = new int[N][N];
    84. for (int i = 0; i < N; i++) {
    85. fmap[i][i] = arr[i];
    86. }
    87. for (int startCol = 1; startCol < N; startCol++) {
    88. int L = 0;
    89. int R = startCol;
    90. while (R < N) {
    91. fmap[L][R] = Math.max(arr[L] + gmap[L + 1][R], arr[R] + gmap[L][R - 1]);
    92. gmap[L][R] = Math.min(fmap[L + 1][R], fmap[L][R - 1]);
    93. L++;
    94. R++;
    95. }
    96. }
    97. return Math.max(fmap[0][N - 1], gmap[0][N - 1]);
    98. }