完全背包
完全背包
背包容量为 V V V,有 n n n种物品,每种物品有无限多个,第 i i i种物品体积为 c i c_i ci,价值为 w i w_i wi,怎样装填背包使总价值最大?
实际上,完全背包并不代表每种物品可以真正装填“无限”多个,因为存在背包总体积这一限制因素。
分析:闫氏DP分析法
-
状态表示
- 集合:定义数组 d p [ i ] [ j ] dp[i][j] dp[i][j],表示当前选取方案的价值。第 i i i行表示只考虑前 i i i种物品的放置情况, j j j表示当前选取体积不超过 j j j的方案集合。 i n i t ( d p [ 0 ] [ i ] , d p [ j ] [ 0 ] ) = 0 init(dp[0][i],dp[j][0])=0 init(dp[0][i],dp[j][0])=0
- 属性: M a x Max Max
-
状态计算: d p [ i ] [ j ] dp[i][j] dp[i][j]:对于第 i i i种物品:
- 不可选第 i i i种物品:当 v < c [ i ] v<c[i] v<c[i]时,无法装入背包,背包剩余容积不变。集合状态仍为 [ 1 , i − 1 ] [1,i-1] [1,i−1],直接继承自第 i − 1 i-1 i−1种物品且背包容积仍为 j j j方案的价值。 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j]
- 可选第
i
i
i种物品:
- 不选第 i i i种物品:若选第 i i i种物品无法保证最优解,则不选,背包剩余容积不变。集合状态仍为 [ 1 , i − 1 ] [1,i-1] [1,i−1],直接继承自第 i − 1 i-1 i−1种物品且背包容积仍为 j j j方案的价值。 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i−1][j]
- 选 [ 1 , . . . , k , . . . + ∞ ] [1,...,k,...+\infty] [1,...,k,...+∞]个第 i i i种物品:选第 i i i种物品可能导致产生最优解,则选。集合状态变为 [ 1 , i ] [1,i] [1,i],因为第 i i i种物品可被选多次,设选 k k k个第 i i i种物品,则继承自第 i i i种物品且背包容积 j j j减少 k ∗ c [ i ] k*c[i] k∗c[i]方案的价值,并加 k ∗ w [ i ] k*w[i] k∗w[i]。对于每一次选第 i i i种物品,为 d p [ i ] [ j ] = d p [ i ] [ j − c [ i ] ] + w [ i ] dp[i][j]=dp[i][j-c[i]]+w[i] dp[i][j]=dp[i][j−c[i]]+w[i]
-
状态转移方程式: d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − c [ i ] ] + w [ i ] ) dp[i][j]=max(dp[i-1][j],dp[i][j-c[i]]+w[i]) dp[i][j]=max(dp[i−1][j],dp[i][j−c[i]]+w[i])
遍历顺序:物品和背包谁先遍历都可以
void init(){
for(int i=0;i<=n;i++) dp[i][0]=0;
for(int i=0;i<=v;i++) dp[0][j]=0;
}
int dp(){
for(int i=1;i<=n;i++)
for(int j=1;j<=v;j++)
if(c[j]<v) dp[i][j]=max(dp[i-1][j],dp[i][j-c[i]]+w[i]);
else dp[i][j]=dp[i-1][j];
return dp[n][v];
}
时间复杂度 O ( n 3 ) O(n^3) O(n3),空间复杂度 O ( n v ) O(nv) O(nv)
滚动优化
交替滚动
extern int dp[2][v];
int dp(){
int work=0,old=1;
for(int i=1;i<=n;i++){
swap(work,old);
for(int j=1;j<=v;j++)
if(c[i]<=j) dp[work][j]=max(dp[old][j],dp[work][j-c[i]]+w[i]);
else dp[work][j]=dp[old][j];
}
return dp[work][v];
}
自我滚动
遍历顺序:物品背包谁先遍历都可以,且均为顺序遍历
extern int dp[v];
int dp(){
for(int i=1;i<=n;i++)
for(int j=c[i];j<=v;j++)//c[i]之前的不用管
dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
return dp[v];
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具