背包问题
Posted vasairg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了背包问题相关的知识,希望对你有一定的参考价值。
背包问题
来源
完全基于中山纪念中学 宋新波ppt的一次复习
动态规划的关键点
- 最优化原理
子问题最优化结构
- 无后效性
未来与过去无关
- 状态
描述最优解的结构
- 状态转移方程
递归定义最优解的值
- 程序实现
用记忆化搜索或迭代法求解
No.1:01背包
问题
有N种物品和一个容量为V的背包。
第i种物品只有1个,体积是v[i],价值是w[i]。
选择物品装入背包使这些物品的体积总和不超过背包容量,且价值总和最大,求出这个最大价值。
分析
- 状态
(f[i,j])表示用体积为j的背包装前i个物品能获得的最大价值。考虑第i种物品装或不装进行状态转移:
- 装
(f[i-1,j-v[i]]+w[i])(必须满足(j>=v[i]))
- 不装
(f[i-1,j])
- 两种情况取较大值。
- 状态转移方程为:
[f[i,j]=left{
egin{array}{rcl}
0 & &{i=0(边界条件)}f[i-1,j] & &{j<v[i]}max(f[i-1,j],f[i-1,j-v[i]]+w[i])& &{j>=v[i]}\end{array}
ight.
]
- 答案为(f[n,v]),时间复杂度为(O(N*V))。
code
#include <bits/stdc++.h>
using namespace std;
const int Max=1e4+10;
int w[Max],v[Max];
int f[Max][Max]={0};
int main()
{
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>v[i];
for(int i=1; i<=n; i++) cin>>w[i];
for(int i=1; i<=n; i++)
for(int j=0; j<=m; j++)
if(j<v[i]) f[i][j]=f[i-1][j];
else f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
cout<<f[n][m]<<endl;
return 0;
}
No.2:完全背包
问题
有N种物品和一个容量为V的背包。
第i种物品有无穷个,体积是v[i],价值是w[i]。
选择物品装入背包使这些物品的体积总和不超过背包容量,且价值总和最大,求出这个最大价值。
分析
方法一
- 状态:
(f[i,j])表示用体积为j的背包装前i个物品能获得的最大价值。
考虑第(i)个物品装几个来进行状态转移,假设装(x)个,(x)的范围为(0<=x<=j / v[i])
- 状态转移方程:
[f[i,j]=left{
egin{array}{rcl}
0 & &{i=0(边界条件)}max{f[i-1,j-x*v[i]]+x*w[i]}& &{0<=x<=j / v[i]}\end{array}
ight.
]
- 答案为(f[n,v]),时间复杂度为(O(V^2*displaystyle sum^N_{i=1}{frac1{v[i]}}))
code
#include <bits/stdc++.h>
using namespace std;
const int Max=1e4+10;
int w[Max],v[Max];
int f[Max][Max]={0};
int main()
{
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>v[i];
for(int i=1; i<=n; i++) cin>>w[i];
for(int i=1; i<=n; i++)
for(int j=0; j<=m; j++)
for(int x=0; x<=j/v[i]; x++)
f[i][j]=max(f[i][j],f[i-1][j-x*v[i]]+x*w[i]);
cout<<f[n][m]<<endl;
return 0;
}
方法二
- 状态
(f[i,j])表示用体积为j的背包装前(i)个物品能获得的最大价值。
- 考虑第(i)个物品装或不装来进行状态转移:
- 装:
必须满足(j>=v[i]),由于物品有无穷多个,装一次后后面还可以再装,所以状态为(f[i,j-v[i]]+w[i]);
- 不装:
(f[i-1,j])
- 状态转移方程:
[f[i,j]=left{
egin{array}{rcl}
0 & &{i=0(边界条件)}f[i-1,j] & &{j<v[i]}max(f[i-1,j],f[i,j-v[i]]+w[i]) & &{j>=v[i]}\end{array}
ight.
]
- 答案为(f[n,v]),时间复杂度为(O(N*V))。
code
#include <bits/stdc++.h>
using namespace std;
const int Max=1e4+10;
int w[Max],v[Max];
int f[Max][Max]={0};
int main()
{
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>v[i];
for(int i=1; i<=n; i++) cin>>w[i];
for(int i=1; i<=n; i++)
for(int j=0; j<=m; j++)
if(j<v[i]) f[i][j]=f[i-1][j];
else f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i]);
cout<<f[n][m]<<endl;
return 0;
}
No.3:多重背包(未完待续)
以上是关于背包问题的主要内容,如果未能解决你的问题,请参考以下文章