java背包问题模板_动态规划背包问题(模版)

(待补全完整)

01背包

问题描述

有n件物品,每件物品的重量为w[i],价值为c[i]。现有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的价值最大。其中每种物品都有1件。

样例输入

5 8 // n == 5, V == 8

3 5 1 2 2 //w[i] 重量

4 5 2 1 3 //c[i] 价值

结果为 10

代码

package 背包问题;

import java.util.Scanner;

public class 零一背包 {

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

int n = in.nextInt();

int V = in.nextInt();

int[] w = new int[n];

int[] c = new int[n];

int[] dp = new int[V+1];

//输入一组物品的重量

for(int i = 0; i < n; i++){

w[i] = in.nextInt();

}

//输入一组物品的价值

for(int i = 0; i < n; i++){

c[i] = in.nextInt();

}

int maxn = 0;

//核心过程

for(int i = 0; i < n; i++){

for(int v = V; v >= w[i]; v--){

dp[v] = Math.max(dp[v],dp[v - w[i]] + c[i]);

maxn = Math.max(dp[v],maxn);

}

}

System.out.println(maxn);

}

}

完全背包

问题描述

有n种物品,每种物品的单件重量为w[i],价值为c[i]。现在有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的总价值最大。其中每种物品都有无穷件。

这里优化之后与01背包其实很是相似,原理不多讲。主要是记录一下模版

代码

package 背包问题;

import java.util.Scanner;

public class 完全背包 {

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

int n = in.nextInt();

int V = in.nextInt();

int[] w = new int[n];

int[] c = new int[n];

int[] dp = new int[V+1];

//输入一组物品的重量

for(int i = 0; i < n; i++){

w[i] = in.nextInt();

}

//输入一组物品的价值

for(int i = 0; i < n; i++){

c[i] = in.nextInt();

}

int maxn = 0;

for(int i = 0; i < n; i++){

//与01背包相比多了逆序变成了正序的变化

for(int v = w[i]; v <= V; v++){

dp[v] = Math.max(dp[v],dp[v - w[i]] + c[i]);

maxn = Math.max(dp[v],maxn);

}

}

System.out.println(maxn);

}

}

多重背包

问题描述

有n种物品,每种物品的重量为w[i],价值为c[i],数量为s[i]。现有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的价值最大。与01背包的差距就是多了数量的限制。

这里呢,是最初始的模版,也就是直接三重for循环,通过o1背包加了一层循环来写的,直接添加了对数量的限制。

代码

package 背包问题;

import java.util.Scanner;

public class 多重背包 {

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

int n = in.nextInt();

int V = in.nextInt();

int[] w = new int[n];

int[] c = new int[n];

int[] s = new int[n];

int[] dp = new int[V + 1];

//输入一组物品的重量

for (int i = 0; i < n; i++) {

w[i] = in.nextInt();

}

//输入一组物品的价值

for (int i = 0; i < n; i++) {

c[i] = in.nextInt();

}

//输入一组物品的数量

for (int i = 0; i < n; i++) {

s[i] = in.nextInt();

}

//三重循环来进行背包填充

for (int i = 0; i < n; i++) {

for (int j = V; j >= w[i]; j--){

for(int k = 0;k <= s[i] && k * w[i] <= j; k++){

dp[j] = Math.max(dp[j],dp[j - k * w[i]] + k * c[i]);

}

}

}

System.out.println(dp[V]);

}

}

多重背包优化

优化描述

问题同上。上面我们虽然解决了多重背包的问题,但是问题也出现了,我们为了加一个限制,于是乎又加了一重循环,导致复杂度的增加,但是我们可以进行优化。

具体思想就是将多重背包压缩成01背包,拆分s变成s组,可以将1-s的数量与价值进行绑定,相当于变成了01背包。但是这样做的拆分复杂度还是高,所以具体就是用到了二进制优化的思想。

代码

package 背包问题;

import java.util.Scanner;

public class 多重背包优化 {

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

int n = in.nextInt();

int V = in.nextInt();

int[] w = new int[n];

int[] c = new int[n];

int[] s = new int[n];

int[] dp = new int[V + 1];

//具体输入要求视题目而定可以优化代码

//输入一组物品的重量

for (int i = 0; i < n; i++) {

w[i] = in.nextInt();

}

//输入一组物品的价值

for (int i = 0; i < n; i++) {

c[i] = in.nextInt();

}

//输入一组物品的数量

for (int i = 0; i < n; i++) {

s[i] = in.nextInt();

}

//我们需要对背包进行压缩

int[] newW = new int[5000]; //压缩后的新重量,这里尽量开一个比较大的值,视题目要求

int[] newC = new int[5000]; //压缩后的价值,这里尽量开一个比较大的值,视题目要求

int cnt = 0; // 用来统计我们绑定后数组大小

for(int i = 0; i < n; i++){

for(int k = 1; k <= s[i]; k *= 2){

s[i] -= k;

newW[cnt] = w[i] * k;

newC[cnt] = c[i] * k;

cnt++;

}

//如果s[i]还有剩余继续添加

if(s[i] > 0){

newW[cnt] = w[i] * s[i];

newC[cnt] = c[i] * s[i];

cnt++;

}

}

//然后就是套用我们的01背包模版

for(int i = 0; i < cnt; i++){

for(int j = V; j >= newW[i]; j--){

dp[j] = Math.max(dp[j],dp[j - newW[i]] + newC[i]);

}

}

System.out.println(dp[V]);

}

}

分组背包

题目描述

有 NN 组物品和一个容量是 VV 的背包。每组物品有若干个,同一组内的物品最多只能选一个。每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。

输出最大价值。

这里我们改一下输入格式,我们以如下的输入格式进行代码的编写:

72b1bb40a97522cea44901464a7c29eb.png

代码

package 背包问题;

import java.util.Scanner;

public class 分组背包 {

static int N = 110; //具体范围视题目要求

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

int n = in.nextInt();

int V = in.nextInt();

int[][] w = new int[N][N];

int[][] c = new int[N][N];

int[] s = new int[n];

int[] dp = new int[N];

for(int i = 0; i < n; i++){

//每一组背包有多少的数量

s[i] = in.nextInt();

for(int j = 0; j < s[i]; j++){

w[i][j] = in.nextInt();

c[i][j] = in.nextInt();

}

}

for(int i = 0; i < n; i++){

for(int j = V; j >= 0; j--){

for(int k = 0; k < s[i]; k++){

if(j >= w[i][k]){ //如果我们的背包可以容纳当前组的可选背包的容量

dp[j] = Math.max(dp[j],dp[j - w[i][k]] + c[i][k]);

}

}

}

}

System.out.println(dp[V]);

}

}

混合背包

题目描述

bbe8292569bacb969c4ef043de7abff3.png

解题思路

我们可以进行一个判断,如果是-1进行01背包处理,如果是0进行完全背包处理,至于多重背包,上面也说过了,可以用二进制优化,也加入到01背包里面。这里我们可以用一个背包类来进行存储,然后实现代码,模版如下。

代码

package 背包问题;

import java.util.ArrayList;

import java.util.List;

import java.util.Scanner;

public class 混合背包 {

static class Bag{

int kind; //背包种类

int w; //背包重量或者体积之类的限制

int c; //背包价值

Bag(int kind,int w,int c){

this.kind = kind;

this.w = w;

this.c = c;

}

}

static int N = 1010; //具体大小视题目而定

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

List bags = new ArrayList<>();

int n = in.nextInt();

int V = in.nextInt();

int[] dp = new int[N];

for(int i = 0; i < n; i++){

int w = in.nextInt();

int c = in.nextInt();

int s = in.nextInt();

if(s < 1){

bags.add(new Bag(-1,w,c));

}else if(s == 0){

bags.add(new Bag(0,w,c));

}else{

//如果是多重背包则进行二进制优化

for(int j = 1; j <= s; j *= 2){

s -= j;

bags.add(new Bag(-1,w * j,c * j));

}

if(s > 0) bags.add(new Bag(-1,w * s,c * s));

}

}

//然后就是分成了01背包和完全背包来处理

for(Bag b : bags){

if(b.kind == -1) {

for(int j = V; j >= b.w; j--){

dp[j] = Math.max(dp[j],dp[j - b.w] + b.c);

}

}else{

for(int j = 0; j <= V; j++){

dp[j] = Math.max(dp[j],dp[j - b.w] + b.c);

}

}

}

System.out.println(dp[V]);

}

}

二维费用背包

二维费用背包,其实很好理解,就是原本我们背包只有一个重量的限制,现在可能多了一个体积的限制。

相比一维的01背包其实就多了一重循环,同时我们也可以继续扩展问题,三维费用背包,四维费用背包等等。

b1ca61a27540905730f8b8e3072d7fb7.png

代码

package 背包问题;

import java.util.Scanner;

public class 二维费用背包 {

static int N = 1010; //视题目要求进行修改范围

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

int n = in.nextInt();

int V = in.nextInt();

int M = in.nextInt();

int[][] dp = new int[N][N];

for(int i = 0; i < n; i++){

int v = in.nextInt(); //物品体积

int m = in.nextInt(); //物品重量

int c = in.nextInt(); //物品价值

for(int j = V; j >= v; j--){

for(int k = M; k >= m; k--){

dp[j][k] = Math.max(dp[j][k],dp[j - v][k - m] + c);

}

}

}

System.out.println(dp[V][M]);

}

}

背包问题方案数

求背包问题的方案

依赖背包问题

参考资料

《算法笔试》

《背包九讲》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值