动态规划-背包问题
0-1背包
解决思路:
每次尝试往背包里新加一个物品,如果装不下,则将体积组建增大。当能装下时候,用当前体积减去新装入的这个物品的体积,得到除了当前这个物品的体积,在之前的已知解中查找这个体积容纳的最大价值,用这个最大价值加上当前物品的价值就是新的最大价值。
#include<iostream>
#include<stdio.h>
using namespace std;
void Knapsack(int n,int c,int *w,int *p){
int f[100][100];
int i=0,j=0;
for(i=1;i<=n;i++){ # n 是物品的个数,这一层循环尝试逐个添加物品
for(j=1;j<=c;j++){ # j是当前体积,逐渐增加体积 ,观察体积变大后放入当前物品j之后价值的变化
f[i][j]=f[i-1][j]; # i-1 是上一个物品, [j] 当前体积,f[i-1][j] 也就是上一个物品当前体积下的最大价值
if(j>=w[i]){ # j 是当前体积, w[i] 是当前物品的体积,因为要往背包里放入当前物品,所以当前假定的体积要大于物品的体积
f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+p[i]); # 如果能放下,要查找除掉当前物品的体积之后的体积能装的最大的价值, f[i-1][*] 是添加上一个物品的已知解空间,
# w[i] 是当前物品的体积, j 是当前假设背包的体积 j-[w[i]] 也就是当前背包的体积去掉当前物品的体积, f[i-1][j-w[i]] 就是去掉当前物品体积后还剩下的体积装的最大价值
# f[i-1][j-w[i]]+p[i] 即是装上当前物品后的最大价值
# f[i-1][j] 是不转入当前物品的最大价值,一般不会取这个值,除非有物品价值为负数或者0
}
}
}
cout<<"背包能装的最大价值是:" << f[i-1][j-1] <<endl;
}
int main(){
int n;
int c;
c=10; //背包容量c
n=5; //物体个数n
int w[6]={0,2,2,6,5,4}; //物品体积
int p[6]={0,6,3,5,4,6}; //物品价值
Knapsack(n,c,w,p);
}
分组背包
分组背包与01背包的区别是,分组背包需要在一组商品中只能选择一个。
一组商品中可以包含n个商品。在01背包中选择一个物品加入背包观察价值是否变化,在分组背包中,则是尝试将一组物品组个尝试加入背包,观察最大价值的是哪个。
分组背包时间复杂度:
\(O(n) = \sum\limits_{i=1}^{m} C*M[i]\)
参数 | 说明 |
---|---|
C | 容积 |
M[i] | 第i个分组中物品的个数 |
m | 分组个数 |
如果背包的体积为C,物品的个数为N,则算法复杂度为:
$ O(n) = C * N $