动态规划问题
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一样 但它的特点是每个物品可以无限选用。
思路:
- 不装入第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]);
}
}
}
}
}