背包问题汇总

时间:2024-10-06 21:16:30

01背包问题:求可承受重量下装载的最大价值

给你一个可装载重量为W的背包和N个物品,每个物品有重量和价值两个属性。其中第i个物品的重量为wt[i],价值为val[i],现在让你用这个背包装物品,最多能装的价值是多少?

  1. public int maxValue(int W,int N,int[] weight,int[] val){
  2. int[][] dp=new int[N+1][W+1];
  3. for(int i=1;i<=N;i++){
  4. for(int w=1;w<=W;w++){
  5. if(w<weight[i-1]){
  6. //当背包容量装不下时,只能选择不装入背包
  7. dp[i][w]=dp[i-1][w];
  8. }else{
  9. //根据价值选择是否装入背包
  10. dp[i][w]=(dp[i-1][w-weight[i-1]]+val[i-1],dp[i-1][w]);
  11. }
  12. }
  13. }
  14. return dp[N][W];
  15. }

子集背包问题:求能否使用给定的元素将背包装满

思路:求出数组的总和sum,令sum/2为背包的可承载重量,将元素装入该背包中,判断是否能恰好将背包装满。

  1. class Solution {
  2. public boolean canPartition(int[] nums) {
  3. int sum=0;
  4. for(int num:nums) sum+=num;
  5. if(sum%2!=0) return false;
  6. sum/=2;
  7. int n=nums.length;
  8. boolean[][] dp=new boolean[n+1][sum+1];
  9. for(int i=0;i<=n;i++){
  10. dp[i][0]=true;
  11. }
  12. for(int i=1;i<=n;i++){
  13. for(int j=1;j<=sum;j++){
  14. if(j<nums[i-1]){
  15. dp[i][j]=dp[i-1][j];
  16. }else{
  17. dp[i][j]=dp[i-1][j]|dp[i-1][j-nums[i-1]];
  18. }
  19. }
  20. }
  21. return dp[n][sum];
  22. }
  23. }

完全背包问题:求当元素可重复使用时,装满背包的组合个数

思路: 物品的数量是无限的,完全背包问题。

  1. class Solution {
  2. public int change(int amount, int[] coins) {
  3. int n=coins.length;
  4. int[][] dp=new int[n+1][amount+1];
  5. for(int i=0;i<=n;i++){
  6. dp[i][0]=1;
  7. }
  8. for(int i=1;i<=n;i++){
  9. for(int j=1;j<=amount;j++){
  10. if(j<coins[i-1]){
  11. dp[i][j]=dp[i-1][j];
  12. }else{
  13. dp[i][j]=dp[i-1][j]+dp[i][j-coins[i-1]];
  14. }
  15. }
  16. }
  17. return dp[n][amount];
  18. }
  19. }

多重背包问题:当元素可重复使用时,求可承受重量下装载的最大价值

题目
有N种物品和一个容量为V的背包。第i种物品最多有p [ i ]件可用,每件费用是w [ i ],价值是v [ i ] 。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

解法一:自上而下填表法,超时

  1. public static void main(String[] args) {
  2. int[] P={8,2,1,7,1,18,4}; //价值
  3. int[] V={3,4,3,9,4,5,4}; //重量
  4. int[] M={1,1,1,1,1,1,1}; //数量
  5. int T = 6;
  6. int[][] dp = new int[P.length + 1][T + 1];
  7. for (int i = 0; i < P.length; i++){
  8. for (int j = 0; j <= T; j++){
  9. for (int k = 0; k <= M[i] && k * V[i] <= j; k++){
  10. dp[i+1][j] = (dp[i+1][j], dp[i][j-k * V[i]] + k * P[i]);
  11. }
  12. }
  13. }
  14. (dp[P.length][T]);
  15. }

解法二:优化位01背包问题

  1. for (int i = 1; i <= n; i++) {
  2. int num = min(p[i], V / w[i]);
  3. for (int k = 1; num > 0; k <<= 1) {
  4. if (k > num) k = num;
  5. num -= k;
  6. for (int j = V; j >= w[i] * k; j--)
  7. f[j] = max(f[j], f[j - w[i] * k] + v[i] * k);
  8. }
  9. }