package 第03期.mca_10; import java.util.ArrayList; // 本题测试链接 : https://leetcode.com/problems/burst-balloons/ public class Code03_BurstBalloons { public static int maxCoins(int[] nums) { int n = nums.length; // 3 5 2 // 1 3 5 2 1 int[] arr = new int[n + 2]; arr[0] = 1; arr[n + 1] = 1; // 1 3 5 2 1 for (int i = 0; i < n; i++) { arr[i + 1] = nums[i]; } // 3 5 2 3 // 1 3 5 2 1 // 0 1 2 3 4 return hit(arr, 1, n); } // arr[l...r]范围上,选择最优的打爆顺序,返回最大的得分! // 想要调用递归,必须满足如下条件 : // arr[l-1]的气球,一定没爆! // arr[r+1]的气球,一定没爆! public static int hit(int[] arr, int l, int r) { if (l == r) { // l...r 只有一个气球了! return arr[l - 1] * arr[l] * arr[r + 1]; } // l < r 不只一个气球 // 可能性1 : 最后打爆l位置的气球 int p1 = hit(arr, l + 1, r) + arr[l - 1] * arr[l] * arr[r + 1]; // 可能性2 : 最后打爆r位置的气球 int p2 = hit(arr, l, r - 1) + arr[l - 1] * arr[r] * arr[r + 1]; int ans = Math.max(p1, p2); for (int m = l + 1; m < r; m++) { // 尝试中间每一个气球,都最后打爆 int left = hit(arr, l, m - 1); int right = hit(arr, m + 1, r); int mid = arr[l - 1] * arr[m] * arr[r + 1]; int curAns = left + right + mid; ans = Math.max(ans, curAns); } return ans; } public static void main(String[] args) { int[] arr = { 3, 3, 4, 3, 3 }; System.out.println(maxCoins(arr)); ArrayList> paths = maxCoins2(arr); for (ArrayList path : paths) { for (int num : path) { System.out.print(num + " "); } System.out.println(); } } public static ArrayList> maxCoins2(int[] arr) { int N = arr.length; int[] help = new int[N + 2]; help[0] = 1; help[N + 1] = 1; for (int i = 0; i < N; i++) { help[i + 1] = arr[i]; } int[][] dp = new int[N + 2][N + 2]; for (int i = 1; i <= N; i++) { dp[i][i] = help[i - 1] * help[i] * help[i + 1]; } for (int L = N; L >= 1; L--) { for (int R = L + 1; R <= N; R++) { int ans = help[L - 1] * help[L] * help[R + 1] + dp[L + 1][R]; ans = Math.max(ans, help[L - 1] * help[R] * help[R + 1] + dp[L][R - 1]); for (int i = L + 1; i < R; i++) { ans = Math.max(ans, help[L - 1] * help[i] * help[R + 1] + dp[L][i - 1] + dp[i + 1][R]); } dp[L][R] = ans; } } System.out.println("结果 : " + dp[1][N]); ArrayList> ans = new ArrayList<>(); ArrayList path = new ArrayList<>(); generatePath2(dp, help, 1, N, N, path, ans); return ans; } public static int pi; // 回溯!倒着填路径 public static void generatePath1(int[][] dp, int[] arr, int l, int r, int[] path) { if (l == r) { path[pi--] = l; } else { if (dp[l + 1][r] + arr[l - 1] * arr[l] * arr[r + 1] == dp[l][r]) { path[pi--] = l; generatePath1(dp, arr, l + 1, r, path); } else if (dp[l][r - 1] + arr[l - 1] * arr[r] * arr[r + 1] == dp[l][r]) { path[pi--] = r; generatePath1(dp, arr, l, r - 1, path); } else { for (int m = l + 1; m < r; m++) { int left = dp[l][m - 1]; int right = dp[m + 1][r]; int mid = arr[l - 1] * arr[m] * arr[r + 1]; if (left + right + mid == dp[l][r]) { path[pi--] = m; generatePath1(dp, arr, l, m - 1, path); generatePath1(dp, arr, m + 1, r, path); break; } } } } } // 回溯!倒着填路径 public static void generatePath2(int[][] dp, int[] arr, int l, int r, int n, ArrayList path, ArrayList> ans) { if (l == r) { path.add(l); if (path.size() == n) { addPath(ans, path); } } else { if (dp[l + 1][r] + arr[l - 1] * arr[l] * arr[r + 1] == dp[l][r]) { ArrayList p = new ArrayList<>(path); p.add(l); generatePath2(dp, arr, l + 1, r, n, p, ans); } if (dp[l][r - 1] + arr[l - 1] * arr[r] * arr[r + 1] == dp[l][r]) { ArrayList p = new ArrayList<>(path); p.add(r); generatePath2(dp, arr, l, r - 1, n, p, ans); } for (int m = l + 1; m < r; m++) { int left = dp[l][m - 1]; int right = dp[m + 1][r]; int mid = arr[l - 1] * arr[m] * arr[r + 1]; if (left + right + mid == dp[l][r]) { // 可以先左、后右 ArrayList p1 = new ArrayList<>(path); p1.add(m); generatePath2(dp, arr, l, m - 1, n, p1, ans); generatePath2(dp, arr, m + 1, r, n, p1, ans); // 也可以先右、后左 ArrayList p2 = new ArrayList<>(path); p2.add(m); generatePath2(dp, arr, m + 1, r, n, p2, ans); generatePath2(dp, arr, l, m - 1, n, p2, ans); } } } } public static void addPath(ArrayList> ans, ArrayList path) { ArrayList curPath = new ArrayList<>(); for (int i = path.size() - 1; i >= 0; i--) { curPath.add(path.get(i) - 1); } ans.add(curPath); } // // public static int maxCoins0(int[] arr) { // // [3,2,1,3] // // [1,3,2,1,3,1] // int N = arr.length; // int[] help = new int[N + 2]; // for (int i = 0; i < N; i++) { // help[i + 1] = arr[i]; // } // help[0] = 1; // help[N + 1] = 1; // return func(help, 1, N); // } // // // L-1位置,和R+1位置,永远不越界,并且,[L-1] 和 [R+1] 一定没爆呢! // // 返回,arr[L...R]打爆所有气球,最大得分是什么 // public static int func(int[] arr, int L, int R) { // if (L == R) { // return arr[L - 1] * arr[L] * arr[R + 1]; // } // // 尝试每一种情况,最后打爆的气球,是什么位置 // // L...R // // L位置的气球,最后打爆 // int max = func(arr, L + 1, R) + arr[L - 1] * arr[L] * arr[R + 1]; // // R位置的气球,最后打爆 // max = Math.max(max, func(arr, L, R - 1) + arr[L - 1] * arr[R] * arr[R + 1]); // // 尝试所有L...R,中间的位置,(L,R) // for (int i = L + 1; i < R; i++) { // // i位置的气球,最后打爆 // int left = func(arr, L, i - 1); // int right = func(arr, i + 1, R); // int last = arr[L - 1] * arr[i] * arr[R + 1]; // int cur = left + right + last; // max = Math.max(max, cur); // } // return max; // } // // public static int maxCoins1(int[] arr) { // if (arr == null || arr.length == 0) { // return 0; // } // if (arr.length == 1) { // return arr[0]; // } // int N = arr.length; // int[] help = new int[N + 2]; // help[0] = 1; // help[N + 1] = 1; // for (int i = 0; i < N; i++) { // help[i + 1] = arr[i]; // } // return process(help, 1, N); // } // // // 打爆arr[L..R]范围上的所有气球,返回最大的分数 // // 假设arr[L-1]和arr[R+1]一定没有被打爆 // public static int process(int[] arr, int L, int R) { // if (L == R) {// 如果arr[L..R]范围上只有一个气球,直接打爆即可 // return arr[L - 1] * arr[L] * arr[R + 1]; // } // // 最后打爆arr[L]的方案,和最后打爆arr[R]的方案,先比较一下 // int max = Math.max(arr[L - 1] * arr[L] * arr[R + 1] + process(arr, L + 1, R), // arr[L - 1] * arr[R] * arr[R + 1] + process(arr, L, R - 1)); // // 尝试中间位置的气球最后被打爆的每一种方案 // for (int i = L + 1; i < R; i++) { // max = Math.max(max, arr[L - 1] * arr[i] * arr[R + 1] + process(arr, L, i - 1) + process(arr, i + 1, R)); // } // return max; // } // // public static int maxCoins2(int[] arr) { // if (arr == null || arr.length == 0) { // return 0; // } // if (arr.length == 1) { // return arr[0]; // } // int N = arr.length; // int[] help = new int[N + 2]; // help[0] = 1; // help[N + 1] = 1; // for (int i = 0; i < N; i++) { // help[i + 1] = arr[i]; // } // int[][] dp = new int[N + 2][N + 2]; // for (int i = 1; i <= N; i++) { // dp[i][i] = help[i - 1] * help[i] * help[i + 1]; // } // for (int L = N; L >= 1; L--) { // for (int R = L + 1; R <= N; R++) { // int ans = help[L - 1] * help[L] * help[R + 1] + dp[L + 1][R]; // ans = Math.max(ans, help[L - 1] * help[R] * help[R + 1] + dp[L][R - 1]); // for (int i = L + 1; i < R; i++) { // ans = Math.max(ans, help[L - 1] * help[i] * help[R + 1] + dp[L][i - 1] + dp[i + 1][R]); // } // dp[L][R] = ans; // } // } // return dp[1][N]; // } }