动态规划常见模型之背包专题

背包问题专题

背包问题常见以下几种

01背包
模型特点:每种物品只有一个,且要么选要么不选,有01两种状态因而以01得名。有限制范围,常见体积或者重量限制,一般用二维数组dp[i][j]表示状态,其中第一个维度表示可选范围,第二个维度表示容量等限制范围。

完全背包
模型特点:与01背包相似,唯一不同的是,完全背包的物品是由无限个。

01背包问题

题目描述
给定N个物品,每个物品有一个重量W和一个价值V.你有一个能装M重量的背包.问怎么装使得所装价值最大.每个物品只有一个.
输入
输入的第一行包含两个整数n, m,分别表示物品的个数和背包能装重量。
以后N行每行两个数Wi和Vi,表示物品的重量和价值
输出
输出1行,包含一个整数,表示最大价值。
样例输入
4 5
2 3
1 2
3 4
2 2

先以样例数据来写帮助了解
解法一递归


package 动态规划;
public class _01背包问题_递归 {
    static int []w= {2,1,3,2 };//重量表
    static int []v= {3,2,4,2};//价值表
    static int n=4;//物品数量
    static int W=5;//背包最大承重量
    //当前选到第i个物品 剩余ww的承重量
    static int dfs(int i, int ww) {
        if(ww<=0) return 0;//装不进去了
        if(i==n) {//没东西可选了
            return 0;
        }
        int v2=dfs(i+1,ww);//不选择该物品
        if(w[i]<=ww) {
            int v1=v[i]+dfs(i+1,ww-w[i]);
            return Math.max(v1, v2);
        }else {
            //装不下 不选 返回v2子树
            return v2;
        }
        
    }
    public static void main(String[] args) {
        int ww=W;
        int ans=dfs(0,ww);
        System.out.println(ans);
    }
}

解法二、记忆型递归


package 动态规划;
import java.util.Arrays;
public class _01背包问题_记忆型递归 {
    static int []w= {2,1,3,2 };//重量表
    static int []v= {3,2,4,2};//价值表
    static int n=4;//物品数量
    static int W=5;//背包最大承重量
    //当前选到第i个物品 剩余ww的承重量
    static int[][]ret;
    static int dfs(int i, int ww) {
        if(ww<=0) return 0;//装不进去了
        if(i==n) {//没东西可选了
            return 0;
        }
        //计算前先查询
        if(ret[i][ww]>=0) {
            return ret[i][ww];
        }
        //返回前先记忆状态
        int v2=dfs(i+1,ww);//不选择该物品
        int ans= 0;
        if(w[i]<=ww) {
            int v1=v[i]+dfs(i+1,ww-w[i]);//选择该物品
            ans=Math.max(v1, v2);
        }else {
            ans=v2;
        }
        ret[i][ww]=ans;
        return ret[i][ww];
    }
    public static void main(String[] args) {
        int ww=W;
        ret =new int[n][W+1];
        //初始化为-1
        for(int i=0;i<n;i++) {
            Arrays.fill(ret[i], -1);
        }
        for(int i=0;i<n;i++) {
            for(int j=1;j<=W;j++) {
                System.out.print(ret[i][j]);
            }
            System.out.println();
        }
        int ans=dfs(0,ww);
        System.out.println(ans);
    }
}

解法三、dp

/*
题目描述
给定N个物品,每个物品有一个重量W和一个价值V.你有一个能装M重量的背包.问怎么装使得所装价值最大.每个物品只有一个.
输入
输入的第一行包含两个整数n, m,分别表示物品的个数和背包能装重量。
以后N行每行两个数Wi和Vi,表示物品的重量和价值
输出
输出1行,包含一个整数,表示最大价值。
样例输入
3 5
2 3
3 5
4 7
样例输出
8
 
4 5
2 3
1 2
3 4
2 2
得到的dp矩阵:
0 0 3 3 3 3
0 2 3 5 5 5
0 2 3 5 6 7
0 2 3 5 6 7
 *
 */

在这里插入图片描述

 package 动态规划;
import java.util.Scanner;
public class _01背包问题_动态规划 {
    public static void main(String[] args) {
        Scanner reader=new Scanner(System.in);
        int n=reader.nextInt();//物品个数
        int m=reader.nextInt();//背包承重量
        int[] w=new int[n];//存放每个物品的重量
        int[] v=new int[n];//存放每个物品的价值
        for(int i=0;i<n;i++) {
            w[i]=reader.nextInt();
            v[i]=reader.nextInt();
//dp[i][j]中第一个维度表示可选范围 第二个维度表示容量
        }
        int [][]dp=new int[n][m+1];
        //初始化dp数组第一行
        for(int i=0;i<=m;i++) {//w[0]<i 中的i刚好可以表示背包容量
            if(w[0]<=i) {//放得下0号物品
                dp[0][i]=v[0];
            }
        }
        for(int i=1;i<n;i++) {
            for(int j=0;j<=m;j++) {
                if(w[i]<=j) {
                    int v1=dp[i-1][j];//不要当前这个物品
                    int v2=dp[i-1][j-w[i]]+v[i];//要当前这个物品
                    dp[i][j]=Math.max(v1, v2);
                }else {
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
        System.out.println(dp[n-1][m]);
//      for(int i=0;i<n;i++) {
//          for(int j=0;j<=m;j++) {
//              System.out.print(dp[i][j]+" ");
//              }
//          System.out.println();
//      }

完全背包问题

/*
有 N 种物品和一个容量是 V
的背包,每种物品都有无限件可用。
第 i种物品的体积是 vi,价值是 wi
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V
,用空格隔开,分别表示物品种数和背包容积。
接下来有 N
行,每行两个整数 vi,wi,用空格隔开,分别表示第 i
种物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
10
链接:
https://www.acwing.com/problem/content/description/3/
 */
package 动态规划;
import java.util.Scanner;
public class 完全背包问题 {
    public static void main(String[] args) {
        Scanner reader=new Scanner(System.in);
        int n=reader.nextInt();//物品个数
        int m=reader.nextInt();//背包承重量
        int[] w=new int[n];//存放每个物品的重量
        int[] v=new int[n];//存放每个物品的价值
        for(int i=0;i<n;i++) {
            w[i]=reader.nextInt();
            v[i]=reader.nextInt();
        }
        int[][] dp=new int[n][m+1];
        //初始化dp数组第一行
        for(int i=0;i<m;i++) {
            if(w[0]<=i) {
                dp[0][i]=v[0]+dp[0][i-w[0] ];
            }
            
        }
        for(int i=1;i<n;i++) {//i表示行号 同时也是物品号
            for(int j=1;j<=m;j++) {//j表示列好 同时也是背包容量
                if(w[i]<=j) {
                    int v1=v[i]+dp[i][j-w[i]];//选当前物品
                    int v2=dp[i-1][j];
                    dp[i][j]=Math.max(v1,v2);
                }else {
                    dp[i][j]=dp[i-1][j];
                }
                
            }
        }
//      for(int i=0;i<n;i++) {
//          for(int j=1;j<=m;j++) {
//              System.out.print(dp[i][j]+" ");
//          }
//          System.out.println();
//      }
        System.out.println(dp[n-1][m]);
        
    }
}
    }
}
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值