modify code

master
algorithmzuo 1 year ago
parent c54d9612b7
commit 7f88ec6074

@ -0,0 +1,143 @@
package 03.mca_10;
// 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额
// 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0
// 假设每一种面额的硬币有无限个
// 题目数据保证结果符合 32 位带符号整数
// 测试链接 : https://leetcode.cn/problems/coin-change-ii/
public class Code01_CoinChange {
public static int change1(int aim, int[] arr) {
return ways(arr, 0, aim);
}
// arr[i....]所有的面值,每一种面值可以使用无限张
// 找的钱数是r请返回方法数
public static int ways(int[] arr, int i, int r) {
if (r < 0) {
return 0;
}
// r >= 0
if (i == arr.length) {
// 已经没有面值了! 0元1种不用任何钱
// >0 元0种方法
return r == 0 ? 1 : 0;
}
// r >= 0 并且 还有面值
// 可能性1 : 就是不用当前面值了,
int p1 = ways(arr, i + 1, r);
// 可能性2 : 用1张当前的面值
int p2 = ways(arr, i, r - arr[i]);
return p1 + p2;
}
public static int change2(int aim, int[] arr) {
int n = arr.length;
int[][] dp = new int[n][aim + 1];
for (int i = 0; i < n; i++) {
for (int r = 0; r <= aim; r++) {
dp[i][r] = -1; // -1表示所有状态没算过!
}
}
return ways2(arr, 0, aim, dp);
}
public static int ways2(int[] arr, int i, int r, int[][] dp) {
if (r < 0) {
return 0;
}
if (i == arr.length) {
return r == 0 ? 1 : 0;
}
if (dp[i][r] != -1) {
return dp[i][r];
}
int p1 = ways2(arr, i + 1, r, dp);
int p2 = ways2(arr, i, r - arr[i], dp);
int ans = p1 + p2;
dp[i][r] = ans;
return ans;
}
// public static int change1(int aim, int[] arr) {
// return process1(arr, 0, aim);
// }
//
// public static int process1(int[] arr, int i, int j) {
// if (j < 0) {
// return 0;
// }
// if (i == arr.length) {
// return j == 0 ? 1 : 0;
// }
// return process1(arr, i + 1, j) + process1(arr, i, j - arr[i]);
// }
//
// public static int change2(int aim, int[] arr) {
// int n = arr.length;
// int[][] dp = new int[n][aim + 1];
// for (int i = 0; i < n; i++) {
// for (int j = 0; j <= aim; j++) {
// dp[i][j] = -1;
// }
// }
// return process2(arr, 0, aim, dp);
// }
//
// public static int process2(int[] arr, int i, int j, int[][] dp) {
// if (j < 0) {
// return 0;
// }
// if (i == arr.length) {
// return j == 0 ? 1 : 0;
// }
// if (dp[i][j] != -1) {
// return dp[i][j];
// }
// int ans = process2(arr, i + 1, j, dp) + process2(arr, i, j - arr[i], dp);
// dp[i][j] = ans;
// return ans;
// }
//
public static int change3(int aim, int[] arr) {
int n = arr.length;
int[][] dp = new int[n + 1][aim + 1];
dp[n][0] = 1;
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j <= aim; j++) {
dp[i][j] = dp[i + 1][j];
if (j - arr[i] >= 0) {
dp[i][j] += dp[i][j - arr[i]];
}
}
}
return dp[0][aim];
}
public static int change4(int aim, int[] arr) {
int n = arr.length;
int[] dp = new int[aim + 1];
dp[0] = 1;
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j <= aim; j++) {
if (j - arr[i] >= 0) {
dp[j] += dp[j - arr[i]];
}
}
}
return dp[aim];
}
// public static int change5(int aim, int[] arr) {
// int n = arr.length;
// int[] dp = new int[aim + 1];
// dp[0] = 1;
// for (int i = n - 1; i >= 0; i--) {
// for (int j = arr[i]; j <= aim; j++) {
// dp[j] += dp[j - arr[i]];
// }
// }
// return dp[aim];
// }
}

@ -0,0 +1,195 @@
package 03.mca_10;
// 给定两个字符串 text1 和 text2返回这两个字符串的最长 公共子序列 的长度
// 如果不存在 公共子序列 ,返回 0
// 一个字符串的 子序列 是指这样一个新的字符串:
// 它是由原字符串在不改变字符的相对顺序的情况下
// 删除某些字符(也可以不删除任何字符)后组成的新字符串
// 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列
// 两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列
// 这个问题leetcode上可以直接测
// 链接https://leetcode.cn/problems/longest-common-subsequence/
public class Code02_LongestCommonSubsequence {
public static int longestCommonSubsequence1(String str1, String str2) {
char[] s1 = str1.toCharArray();
char[] s2 = str2.toCharArray();
return process(s1, s2, s1.length - 1, s2.length - 1);
}
// s1[0....i]
// s2[0....j]
// 返回这两段对应的情况下,最长公共子序列长度
public static int process(char[] s1, char[] s2, int i, int j) {
if (i == -1 || j == -1) {
return 0;
}
// i>=0, j>=0
// X i X j
int p1 = process(s1, s2, i - 1, j - 1);
// V i X j
int p2 = process(s1, s2, i, j - 1);
// X i V j
int p3 = process(s1, s2, i - 1, j);
// V i V j
int p4 = 0;
if (s1[i] == s2[j]) {
p4 = p1 + 1;
}
return Math.max(Math.max(p1, p2), Math.max(p3, p4));
}
public static int longestCommonSubsequence2(String str1, String str2) {
char[] s1 = str1.toCharArray();
char[] s2 = str2.toCharArray();
int n = s1.length;
int m = s2.length;
int[][] dp = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
dp[i][j] = -1;
}
}
return process2(s1, s2, s1.length - 1, s2.length - 1, dp);
}
// s1[0....i]
// s2[0....j]
// 返回这两段对应的情况下,最长公共子序列长度
public static int process2(char[] s1, char[] s2, int i, int j, int[][] dp) {
if (i == -1 || j == -1) {
return 0;
}
if (dp[i][j] != -1) {
return dp[i][j];
}
int p1 = process2(s1, s2, i - 1, j - 1, dp);
int p2 = process2(s1, s2, i, j - 1, dp);
int p3 = process2(s1, s2, i - 1, j, dp);
int p4 = 0;
if (s1[i] == s2[j]) {
p4 = p1 + 1;
}
int ans = Math.max(Math.max(p1, p2), Math.max(p3, p4));
dp[i][j] = ans;
return ans;
}
// public static int longestCommonSubsequence1(String s1, String s2) {
// if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {
// return 0;
// }
// char[] str1 = s1.toCharArray();
// char[] str2 = s2.toCharArray();
// // 尝试
// return process1(str1, str2, str1.length - 1, str2.length - 1);
// }
//
// // str1[0...i]和str2[0...j],这个范围上最长公共子序列长度是多少?
// // 可能性分类:
// // a) 最长公共子序列一定不以str1[i]字符结尾、也一定不以str2[j]字符结尾
// // b) 最长公共子序列可能以str1[i]字符结尾、但是一定不以str2[j]字符结尾
// // c) 最长公共子序列一定不以str1[i]字符结尾、但是可能以str2[j]字符结尾
// // d) 最长公共子序列必须以str1[i]字符结尾、也必须以str2[j]字符结尾
// // 注意a)、b)、c)、d)并不是完全互斥的,他们可能会有重叠的情况
// // 但是可以肯定,答案不会超过这四种可能性的范围
// // 那么我们分别来看一下,这几种可能性怎么调用后续的递归。
// // a) 最长公共子序列一定不以str1[i]字符结尾、也一定不以str2[j]字符结尾
// // 如果是这种情况那么有没有str1[i]和str2[j]就根本不重要了,因为这两个字符一定没用啊
// // 所以砍掉这两个字符,最长公共子序列 = str1[0...i-1]与str2[0...j-1]的最长公共子序列长度(后续递归)
// // b) 最长公共子序列可能以str1[i]字符结尾、但是一定不以str2[j]字符结尾
// // 如果是这种情况那么我们可以确定str2[j]一定没有用要砍掉但是str1[i]可能有用,所以要保留
// // 所以,最长公共子序列 = str1[0...i]与str2[0...j-1]的最长公共子序列长度(后续递归)
// // c) 最长公共子序列一定不以str1[i]字符结尾、但是可能以str2[j]字符结尾
// // 跟上面分析过程类似,最长公共子序列 = str1[0...i-1]与str2[0...j]的最长公共子序列长度(后续递归)
// // d) 最长公共子序列必须以str1[i]字符结尾、也必须以str2[j]字符结尾
// // 同时可以看到可能性d)存在的条件一定是在str1[i] == str2[j]的情况下,才成立的
// // 所以,最长公共子序列总长度 = str1[0...i-1]与str2[0...j-1]的最长公共子序列长度(后续递归) + 1(共同的结尾)
// // 综上,四种情况已经穷尽了所有可能性。四种情况中取最大即可
// // 其中b)、c)一定参与最大值的比较,
// // 当str1[i] == str2[j]时a)一定比d)小所以d)参与
// // 当str1[i] != str2[j]时d)压根不存在所以a)参与
// // 但是再次注意了!
// // a)是str1[0...i-1]与str2[0...j-1]的最长公共子序列长度
// // b)是str1[0...i]与str2[0...j-1]的最长公共子序列长度
// // c)是str1[0...i-1]与str2[0...j]的最长公共子序列长度
// // a)中str1的范围 < b)中str1的范围a)中str2的范围 == b)中str2的范围
// // 所以a)不用求也知道它比不过b)啊因为有一个样本的范围比b)小啊!
// // a)中str1的范围 == c)中str1的范围a)中str2的范围 < c)中str2的范围
// // 所以a)不用求也知道它比不过c)啊因为有一个样本的范围比c)小啊!
// // 至此可以知道a)就是个垃圾,有它没它,都不影响最大值的决策
// // 所以当str1[i] == str2[j]时b)、c)、d)中选出最大值
// // 当str1[i] != str2[j]时b)、c)中选出最大值
// public static int process1(char[] str1, char[] str2, int i, int j) {
// if (i == 0 && j == 0) {
// // str1[0..0]和str2[0..0],都只剩一个字符了
// // 那如果字符相等公共子序列长度就是1不相等就是0
// // 这显而易见
// return str1[i] == str2[j] ? 1 : 0;
// } else if (i == 0) {
// // 这里的情况为:
// // str1[0...0]和str2[0...j]str1只剩1个字符了但是str2不只一个字符
// // 因为str1只剩一个字符了所以str1[0...0]和str2[0...j]公共子序列最多长度为1
// // 如果str1[0] == str2[j]那么此时相等已经找到了公共子序列长度就是1也不可能更大了
// // 如果str1[0] != str2[j],只是此时不相等而已,
// // 那么str2[0...j-1]上有没有字符等于str1[0]呢?不知道,所以递归继续找
// if (str1[i] == str2[j]) {
// return 1;
// } else {
// return process1(str1, str2, i, j - 1);
// }
// } else if (j == 0) {
// // 和上面的else if同理
// // str1[0...i]和str2[0...0]str2只剩1个字符了但是str1不只一个字符
// // 因为str2只剩一个字符了所以str1[0...i]和str2[0...0]公共子序列最多长度为1
// // 如果str1[i] == str2[0]那么此时相等已经找到了公共子序列长度就是1也不可能更大了
// // 如果str1[i] != str2[0],只是此时不相等而已,
// // 那么str1[0...i-1]上有没有字符等于str2[0]呢?不知道,所以递归继续找
// if (str1[i] == str2[j]) {
// return 1;
// } else {
// return process1(str1, str2, i - 1, j);
// }
// } else { // i != 0 && j != 0
// // 这里的情况为:
// // str1[0...i]和str2[0...i]str1和str2都不只一个字符
// // 看函数开始之前的注释部分
// // p1就是可能性c)
// int p1 = process1(str1, str2, i - 1, j);
// // p2就是可能性b)
// int p2 = process1(str1, str2, i, j - 1);
// // p3就是可能性d)如果可能性d)存在即str1[i] == str2[j]那么p3就求出来参与pk
// // 如果可能性d)不存在即str1[i] != str2[j]那么让p3等于0然后去参与pk反正不影响
// int p3 = str1[i] == str2[j] ? (1 + process1(str1, str2, i - 1, j - 1)) : 0;
// return Math.max(p1, Math.max(p2, p3));
// }
// }
//
// public static int longestCommonSubsequence2(String s1, String s2) {
// if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {
// return 0;
// }
// char[] str1 = s1.toCharArray();
// char[] str2 = s2.toCharArray();
// int N = str1.length;
// int M = str2.length;
// int[][] dp = new int[N][M];
// dp[0][0] = str1[0] == str2[0] ? 1 : 0;
// for (int j = 1; j < M; j++) {
// dp[0][j] = str1[0] == str2[j] ? 1 : dp[0][j - 1];
// }
// for (int i = 1; i < N; i++) {
// dp[i][0] = str1[i] == str2[0] ? 1 : dp[i - 1][0];
// }
// for (int i = 1; i < N; i++) {
// for (int j = 1; j < M; j++) {
// int p1 = dp[i - 1][j];
// int p2 = dp[i][j - 1];
// int p3 = str1[i] == str2[j] ? (1 + dp[i - 1][j - 1]) : 0;
// dp[i][j] = Math.max(p1, Math.max(p2, p3));
// }
// }
// return dp[N - 1][M - 1];
// }
}

@ -0,0 +1,271 @@
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<ArrayList<Integer>> paths = maxCoins2(arr);
for (ArrayList<Integer> path : paths) {
for (int num : path) {
System.out.print(num + " ");
}
System.out.println();
}
}
public static ArrayList<ArrayList<Integer>> 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<ArrayList<Integer>> ans = new ArrayList<>();
ArrayList<Integer> 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<Integer> path,
ArrayList<ArrayList<Integer>> 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<Integer> 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<Integer> 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<Integer> 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<Integer> 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<ArrayList<Integer>> ans, ArrayList<Integer> path) {
ArrayList<Integer> 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];
// }
}

@ -0,0 +1,75 @@
package 03.mca_10;
import java.util.Arrays;
// 来自小红书
// 实验室需要配制一种溶液现在研究员面前有n种该物质的溶液
// 每一种有无限多瓶第i种的溶液体积为v[i]里面含有w[i]单位的该物质
// 研究员每次可以选择一瓶溶液,
// 将其倒入另外一瓶(假设瓶子的容量无限),即可以看作将两个瓶子内的溶液合并
// 此时合并的溶液体积和物质含量都等于之前两个瓶子内的之和。
// 特别地如果瓶子A与B的溶液体积相同那么A与B合并之后
// 该物质的含量会产生化学反应使得该物质含量增加x单位
// 研究员的任务是配制溶液体积恰好等于c的且尽量浓的溶液(即物质含量尽量多)
// 研究员想要知道物质含量最多是多少
// 对于所有数据1 <= n, v[i], w[i], x, c <= 1000
public class Code04_ChemicalProblem {
public static int maxValue(int[] v, int[] w, int x, int c) {
int n = v.length;
// dp[0] ? dp[1] ? dp[2] ? dp[c] ?
int[] dp = new int[c + 1];
// dp[i] = -1, 得到i体积目前为止无方案
Arrays.fill(dp, -1);
// 天然有的规格,先填一下
for (int i = 0; i < n; i++) {
// 3 10 dp[3] = 10
// 5 13 dp[5] = 13
// 3 20 dp[3] = 20
if (v[i] <= c) {
dp[v[i]] = Math.max(dp[v[i]], w[i]);
}
}
// 1 ? 2 ? 3 ? c ? dp[1....c]
for (int i = 1; i <= c; i++) {
// i = 10体积
// 1 + 9
// 2 + 8
// 3 + 7
// 4 + 6
// 5 + 5 + x
for (int j = 1; j <= i / 2; j++) {
// dp[10] = dp[1] + dp[9]
// 能得到 能得到
if (dp[j] != -1 && dp[i - j] != -1) {
dp[i] = Math.max(dp[i],
dp[j] + dp[i - j] + (j == i - j ? x : 0));
}
}
}
return dp[c];
}
public static void main(String[] args) {
// 调配溶液
// 规格0 (体积5含量2)
// 规格1 (体积3含量4)
// 规格2 (体积4含量1)
// 合并双方体积不等的情况下 :
// (体积5含量2) + (体积4含量1) = (体积9含量3)
// 合并双方体积相等的情况下 :
// (体积5含量5) + (体积5含量2) = (体积10含量5 + 2 + x)
// x额外增加固定int类参数x= 10
// c一定要得到c体积的溶液含量最大能是多少 ?
int[] v = { 5, 3, 4 };
int[] w = { 2, 4, 1 };
int x = 4;
int c = 16;
// (体积3含量4) + (体积3含量4) = (体积6含量12)
// (体积3含量4) + (体积3含量4) = (体积6含量12)
// (体积6含量12) + (体积6含量12) = (体积12含量28)
// (体积12含量28) + (体积4含量1) = (体积16含量29)
System.out.println(maxValue(v, w, x, c));
}
}
Loading…
Cancel
Save