动态规划---0/1背包问题、完全背包问题、多重背包问题

动态规划问题

0/1背包问题

125.背包问题II

问题描述:有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值. 。领扣链接
特点:这是最简单的背包问题,特点是每个物品只有一件供你选择放还是不放。

状态:

​ F(i, j): 前i个物品放入大小为j的背包中所获得的最大价值

状态递推:对于第i个商品,有一种例外,装不下,两种选择,放或者不放

如果装不下:此时的价值与前i-1个的价值是一样的

F(i,j) = F(i-1,j)

​ 如果可以装入:需要在两种选择中找最大的

F(i, j) = max{F(i-1,j), F(i-1, j - A[i]) + V[i]}

F(i-1,j): 表示不把第i个物品放入背包中, 所以它的价值就是前i-1个物品放入大小为j的背包的最大价值

​ F(i-1, j - A[i]) + V[i]:表示把第i个物品放入背包中,价值增加V[i],但是需要腾出j - A[i]的大小放

第i个商品

初始化:第0行和第0列都为0,表示没有装物品时的价值都为0

​ F(0,j) = F(i,0) = 0

返回值:F(n,m)

public int backPackII(int m, int[] A, int[] V) {
        // write your code here
        int num = A.length;
        if(m == 0 || num == 0)
            return 0;
        //多加一行一列,用于设置初始条件
        int[][] maxValue = new int[num + 1][m + 1];
        //初始化所有位置为0,第一行和第一列都为0,初始条件
        for(int i = 0; i <= num; ++i){
            maxValue[i][0] = 0;
       }
        for(int i = 1; i <= m; ++i){
            maxValue[0][i] = 0;
       }
        for(int i = 1; i <= num; ++i){
            for(int j = 1; j <= m; ++j){
                //第i个商品在A中对应的索引为i-1: i从1开始
 //如果第i个商品大于j,说明放不下, 所以(i,j)的最大价值和(i-1,j)相同
                if(A[i - 1] > j){
                    maxValue[i][j] = maxValue[i - 1][j];
               }
                else{
                    //如果可以装下,分两种情况,装或者不装
 //如果不装,则即为(i-1, j)
 //如果装,需要腾出放第i个物品大小的空间: j - A[i-1],装入之后的最大价值即为(i - 
1, j - A[i-1]) + 第i个商品的价值V[i - 1]
 //最后在装与不装中选出最大的价值
                    int newValue = maxValue[i - 1][j - A[i - 1]]
                    + V[i - 1];
                    maxValue[i][j] = Math.max(newValue
                   , maxValue[i - 1][j]);
               }
           }
       }
        //返回装入前N个商品,物品大小为m的最大价值
        return maxValue[num][m];
   }

92.背包问题

题目:在n个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为m,每个物品的大小为A[i]。领扣链接

public int backPack(int m, int[] A) {
    int n=A.length;
    int[][] arr=new int[n+1][m+1];
    for(int i=0;i<n+1;i++){
        arr[i][0]=0;
    }
    for(int i=0;i< m+1;i++){
        arr[0][i]=0;
    }
    for (int i=1;i<=n;i++){
        for(int j=1;j<m+1;j++){
            if (A[i-1]>j){
                arr[i][j]=arr[i-1][j];

            }else {
                arr[i][j]=Math.max(arr[i-1][j],arr[i-1][j-A[i-1]]+A[i-1]);
            }
        }
    }
    return arr[n][m];
}

完全背包问题

问题描述:有n件物品和容量为m的背包 给出i件物品的重量以及价值 求解让装入背包的物品重量不超过背包容量 且价值最大 。
特点:题干看似与01一样 但它的特点是每个物品可以无限选用

思路:

  1. 不装入第i种物品,即dp[i−1][j],同01背包;
if (A[i-1]>j){
   arr[i][j]=arr[i-1][j];       
}

​ 2.装入第i种物品,此时和01背包不太一样,因为每种物品有无限个(但注意书包限重是有限的),所以此时不应该转移到dp[i−1][j−w[i]]而应该转移到dp[i][j−w[i]],即装入第i种商品后还可以再继续装入第种商品

else {
      arr[i][j]=Math.max(arr[i-1][j],arr[i][j-A[i-1]]+A[i-1]);
}

代码:

public static String completePack(int V,int N,int[] weight,int[] value){
        //初始化动态规划数组
        int[][] dp = new int[N+1][V+1];
        //为了便于理解,将dp[i][0]和dp[0][j]均置为0,从1开始计算
        for(int i=1;i<N+1;i++){
            for(int j=1;j<V+1;j++){
                //如果第i件物品的重量大于背包容量j,则不装入背包
                //由于weight和value数组下标都是从0开始,故注意第i个物品的重量为weight[i-1],价值为value[i-1]
                if(weight[i-1] > j)
                    dp[i][j] = dp[i-1][j];
                else
                    dp[i][j] = Math.max(dp[i-1][j],dp[i][j-weight[i-1]]+value[i-1]);
            }
        }
        //则容量为V的背包能够装入物品的最大值为
        int maxValue = dp[N][V];
        int j=V;
        String numStr="";
        for(int i=N;i>0;i--){
            //若果dp[i][j]>dp[i-1][j],这说明第i件物品是放入背包的
            while(dp[i][j]>dp[i-1][j]){
                numStr = i+" "+numStr;
                j=j-weight[i-1];
            }
            if(j==0)
                break;
        }
        return numStr;
    }

多重背包问题

问题描述:有n件物品和容量为m的背包 给出i件物品的重量以及价值 还有数量 求解让装入背包的物品重量不超过背包容量 且价值最大 。
特点 :它与完全背包有类似点 特点是每个物品都有了一定的数量

例题:有5个物品,标号为1-5,重量分别是[2,2,6,5,4],价值分别是[6,3,5,4,6],5个物品的数量分别为2,1,1,1,2,背包总承受为10。

完全背包转移方程为
 	dp[i][j] = max(dp[i-1][j-w[i]*k]+v[i]*k, dp[i][j]);

代码:

public static int manyPack(int V,int N,int[] weight,int[] value,int[] num){
    //初始化动态规划数组
    int[][] dp = new int[N+1][V+1];
    //为了便于理解,将dp[i][0]和dp[0][j]均置为0,从1开始计算
    for(int i=1;i<N+1;i++){
        for(int j=1;j<V+1;j++){
            //如果第i件物品的重量大于背包容量j,则不装入背包
            //由于weight和value数组下标都是从0开始,故注意第i个物品的重量为weight[i-1],价值为value[i-1]
            if(weight[i-1] > j)
                dp[i][j] = dp[i-1][j];
            else{
                //考虑物品的件数限制
                int maxV = Math.min(num[i-1],j/weight[i-1]);
                for(int k=0;k<maxV+1;k++){
                    dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-k*weight[i-1]]+k*value[i-1]);
                }
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值