基本题型(一):01背包问题(每一件物品可以拿一次或不拿)
题目详情:01背包-AcWing题库
普通的01背包(二维数组)[缺点:内存消耗大,优点:容易理解]
//普通动态规划01背包问题(核心代码)
//定义一个物品类来存储
public static class Article{
public int weight;
public int value;
public Article(){};
public Article(int weight, int value) {
this.weight = weight;
this.value = value;
}
}
//普通二维(第i层的数据与第i-1层的数据有关)
public static void get_dp_tow(int nums,int weight,Article[] articles){
int dp[][]=new int[nums+1][weight+1];
for (int i = 1; i <= nums ; i++) {
for (int j = 1; j <=weight ; j++) {
if(j<articles[i].weight){
dp[i][j]=dp[i-1][j];
continue;
}
dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-articles[i].weight]+articles[i].value);
}
}
System.out.println(dp[nums][weight]);
}
这是01背包的一维优化(改善了二维dp内存消耗大的问题)
//dp二维背包的一维优化
//动态规划的核心代码(动态转移方程)dp[j]=max(dp[j-weight]+value,dp[j])
//内层循环从weight开始进行--的原因是保证每个物品都只相加一次
public static void get_dp_one(int nums,int weight,Article[] articles){
int[] dp=new int[weight+1];
for (int i = 0; i < nums ; i++) {
for (int j = weight; j >=articles[i].weight ; j--) {
dp[j]=Math.max(dp[j-articles[i].weight]+articles[i].value,dp[j]);
}
}
System.out.println(dp[weight]);
}
基本题型(二):完全背包问题(每一件物品可以拿多次(次数不限))
题目详情:3. 完全背包问题 - AcWing题库
(二维与01背包相似)直接上一维优化
//核心代码
public static void Complete_bag(Article[] articles,int weight){
int nums=articles.length;
int[] dp=new int[weight+1];
for (int i = 0; i < nums ; i++) {
for (int j = articles[i].weight; j <=weight ; j++) {
dp[j]=Math.max(dp[j],dp[j-articles[i].weight]+articles[i].value);
}
}
System.out.println(dp[weight]);
}
*j的遍历顺序决定了是01背包还是完全背包(可以画图自行理解)
基本题型(三):完全背包问题(每一件物品的数量确定)
基于对上述题目的理解,不在写二维dp[][]直接上一维优化后的背包
题目详情:多重背包-AcWing题库
//这里建立物品为三个参数:value,weight,nums
public static class Article{
public int value;
public int weight;
public int nums;
public Article(){};
public Article(int value, int weight, int nums) {
this.value = value;
this.weight = weight;
this.nums = nums;
}
}
//(解题思想)每一个物品的不同数量可以当作不同的物品进行求解
public static void Multiple_bag(Article[] articles,int weight){
int nums=articles.length;
int[] dp=new int[weight+1];
for (int i = 0; i < nums ; i++) {
for (int j = weight; j >=articles[i].weight; j--) {
for (int k = 1; k <= articles[i].nums; k++) {
if(j-k*articles[i].weight<0){
break;
}
dp[j]=Math.max(dp[j-k*articles[i].weight]+k*articles[i].value,dp[j]);
}
}
}
System.out.println(dp[weight]);
}
*dp[j]的确定需要对每一件物品的不同数目时的状态进行遍历
*多重背包还有后续优化(不写了)(小编也不是很明白)
基本题型(四):混合背包问题(前三种背包的结合体)
如果前三种背包已经很明白,可以不用看......
题目详情:混合背包-AcWing题库
//背包定义(依旧是三个元素value,weight,nums)
public static class Article{
public int value;
public int weight;
public int nums;
public Article(){};
public Article(int value, int weight, int nums) {
this.value = value;
this.weight = weight;
this.nums = nums;
}
}
//分类讨论每一个物品的类型,进行解题,与前三种背包一样(前三种理解好,这种就没意思了)
public static void Hybrid_bag(Article[] articles,int weight){
int nums=articles.length;
int[] dp=new int[weight+1];
for (int i = 0; i < nums ; i++) {
//这里重新回顾一下三种背包的写法
if (articles[i].nums==-1){
//走01背包
for (int j = weight; j >=articles[i].weight ; j--) {
dp[j]=Math.max(dp[j-articles[i].weight]+articles[i].value,dp[j]);
}
}else if(articles[i].nums==0){
//走完全背包
for (int j = articles[i].weight; j <=weight ; j++) {
dp[j]=Math.max(dp[j],dp[j-articles[i].weight]+articles[i].value);
}
}else {
//走多重背包
for (int j = weight; j >= articles[i].weight; j--) {
for (int k = 1; k <=articles[i].nums ; k++) {
if(j-k*articles[i].weight<0){
break;
}else {
dp[j]=Math.max(dp[j],dp[j-k*articles[i].weight]+k*articles[i].value);
}
}
}
}
}
System.out.println(dp[weight]);
}
*也可以直接调用之前写的函数(易)
基本题型(五):二维费用背包(限制条件变为两个)
题目详情:二维费用背包-AcWing题库
//1.生成物品类,三个成员变量(体积,质量,价值)
public static class Article{
public int volume;
public int weight;
public int value;
public Article(int volume, int weight, int value) {
this.volume = volume;
this.weight = weight;
this.value = value;
}
}
//因为有两个限制条件所以(只能尽可能的优化到二维dp)
//其中dp[i][j]的含义时在i质量,j容积的条件下所能容纳的最大价值
public static void Cost_bag(Article[] articles,int volume,int weight){
int nums=articles.length;
int[][] dp = new int[weight + 1][volume + 1];
for (int i = 0; i < nums ; i++) {
for (int j = weight; j >=articles[i].weight ; j--) {
for (int k = volume; k >=articles[i].volume ; k--) {
dp[j][k]=Math.max(dp[j][k],dp[j-articles[i].weight][k-articles[i].volume]+articles[i].value);
}
}
}
System.out.println(dp[weight][volume]);
}
*对于物品的限制条件越多,会导致dp数组的维度越高
基本题型(六):分组背包问题
题目详情:分组背包
//收取每一件物品的情况两个常量(weight和value)
public static class Article{
public int weight;
public int value;
public Article(int weight, int value) {
this.weight = weight;
this.value = value;
}
}
//收取每一个组的信息为(一个Article的数组)
public static class GroupArticle{
Article[] articles;
public GroupArticle(Article[] articles) {
this.articles = articles;
}
}
//分组背包的核心代码
public static void Group_bag(GroupArticle[] groupArticles,int weight){
//这里解释一下为什么Group=length-1
//因为输入数据作者是从索引为1开始有n个元素,所以length=n+1
//需要对length-1才能获取数字的个数n
//下面的-1操作同理
int Group=groupArticles.length-1;
int[][] dp = new int[Group + 1][weight + 1];
for (int i = 1; i <= Group ; i++) {
//从articles中选取一个物品
Article[] articles=groupArticles[i].articles;
int nums=articles.length-1;
//这里解释一下需要在每一个weight下来找到最合适的value值
for (int j = 1; j <= weight ; j++) {
dp[i][j]=dp[i-1][j];
for (int k = 1; k <= nums ; k++) {
if(j-articles[k].weight>=0){
dp[i][j]=Math.max(dp[i][j],dp[i-1][j-articles[k].weight]+articles[k].value);
}
}
}
}
System.out.println(dp[Group][weight]);
}
分组背包稍微有一点难,不理解的话可以跳过不看
暂时dp规划就更新到这里
后续.......