揹包問題初步總結--01揹包,完全揹包,有順序的完全揹包
阿新 • • 發佈:2022-03-25
public class TestBeiBao2 { //常見的揹包問題有1、組合問題。2、True、False問題。3、最大最小問題。 //1組合問題:dp[i]+=dp[i-num] //2true,false問題:dp[i] = dp[i] or dp[i-num] //3最大最小問題:dp[i] = min(dp[i], dp[i-num]+value[num])或者dp[i] = max(dp[i], dp[i-num]+value[num]) //常見解法 //1分析是否為揹包問題 //2是以上三種揹包問題中的哪一種 //3是0-1揹包問題還是完全揹包問題。也就是題目給的nums陣列中的元素是否可以重複使用 //4如果是組合問題,是否需要考慮元素之間的順序。需要考慮順序有順序的解法,不需要考慮順序又有對應的解法 //常見技巧 //1如果是0-1揹包,即陣列中的元素不可重複使用,nums放在外迴圈,target在內迴圈,且內迴圈倒序; //2如果是完全揹包,即陣列中的元素可重複使用,nums放在外迴圈,target在內迴圈,且內迴圈正序;或者target在外迴圈,nums放在內迴圈,且內迴圈正序 //3如果組合問題需考慮元素之間的順序,需要在上面兩者情況中選擇一種,記住:當外層迴圈遍歷nums時說明nums只可能按遍歷順序排列 //常見問題 //1典型01揹包 //一維陣列(滾動陣列)01揹包 public static void testWeightBagProblem(int[] weight, int[] value, int bagWeight) { int wLen = weight.length; //定義dp陣列:dp[j]表示揹包容量為j時,能獲得的最大價值 int[] dp = new int[bagWeight + 1]; //遍歷順序:先遍歷物品,再遍歷揹包容量 for (int i = 0; i < wLen; i++) { for (int j = bagWeight; j >= weight[i]; j--) { dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]); } } for (int i = 0; i <= bagWeight; i++) { System.out.println(dp[i]); } } @Test public void test1() { int[] weight = {1, 3, 4};//重量 2 3 4 5 9 int[] value = {15, 20, 30};//價值3 4 5 8 10 int bagWight = 4; testWeightBagProblem(weight, value, bagWight); } //2典型完全揹包 public void testCompletePackAnotherWay(int[] weight, int[] value, int bagWeight) { int wLen = weight.length; int[] dp = new int[bagWeight + 1]; //以下兩者遍歷方式都行 //遍歷順序:先遍歷揹包,再遍歷物品 // for (int i = 1; i <= bagWeight; i++){ // 遍歷揹包容量 // for (int j = 0; j < weight.length; j++){ // 遍歷物品 // if (i - weight[j] >= 0){ // dp[i] = Math.max(dp[i], dp[i - weight[j]] + value[j]); // } // } // } //遍歷順序:先遍歷物品,再遍歷揹包容量 for (int i = 0; i < wLen; i++) { for (int j = 1; j <= bagWeight; j++) {//j從0和1都行 因為j=0結果肯定是0(預設值) if (j >= weight[i]) { dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]); } } } for (int i = 0; i <= bagWeight; i++) { System.out.println(dp[i]); } } @Test public void test2() { int[] weight = {1, 3, 4};//重量 2 3 4 5 9 int[] value = {15, 20, 30};//價值3 4 5 8 10 int bagWight = 4; testCompletePackAnotherWay(weight, value, bagWight); } //3有順序的揹包--LeetCode377 //給你一個由 不同 整陣列成的陣列 nums ,和一個目標整數 target 。請你從 nums 中找出並返回總和為 target 的元素組合的個數。 //情況1-順序不同的組合當做相同的組合 public int combinationSum41(int[] nums, int target) { int[] dp = new int[target + 1]; dp[0] = 1; for (int i = 0; i < nums.length; i++) { for (int j = 1; j <= target; j++) { if (j >= nums[i]) { dp[j] += dp[j - nums[i]]; } } } for (int k = 0; k <= target; k++) { System.out.println(dp[k]);//1 1 2 3 4 } return dp[target]; } @Test public void test3() { int[] nums = {1, 2, 3}; int target = 4; combinationSum41(nums, target); } //情況2-順序相同的組合當做不同的組合 public int combinationSum42(int[] nums, int target) { int[] dp = new int[target + 1]; dp[0] = 1; for (int i = 0; i <= target; i++) { for (int j = 0; j < nums.length; j++) { if (i >= nums[j]) { dp[i] += dp[i - nums[j]];//1 1 2 4 7 } } } for (int k = 0; k <= target; k++) { System.out.println(dp[k]); } return dp[target]; } @Test public void test4() { int[] nums = {1, 2, 3}; int target = 4; combinationSum42(nums, target); } }