01背包问题—动态规划
一、问题描述
简述
试设计一个用回溯法搜索子集空间树的函数。该函数的参数包括结点可行性判定函数和上界函数等必要的函数,并将此函数用于解0-1背包问题。 0-1 背包问题描述如下:给定n 种物品和一个背包。物品i 的重量是wi ,其价值为vi ,背包的容量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有2 种选择,即装入背包或不装入背包。不能将物品i 装入背包多次,也不能只装入部分的物品i。
输入
第一行有2个正整数n和c。n是物品数,c是背包的容量。接下来的1 行中有n个正整数,表示物品的价值。第3 行中有n个正整数,表示物品的重量。
输出
将计算出的装入背包物品的最大价值和最优装入方案输出。第一行输出为:Optimal value is
Sample Input
5 10
6 3 5 4 6
2 2 6 5 4
Sample Output
Optimal value is
15
1 1 0 0 1
二、解题思路
动态规划基本思想
如果能够保存已解决的子问题的答案,而在需要时再找出以求得的答案,就可以避免大量重复计算,从而得到多项式时间算法。为了达到这个目的,可以用一个表来记录所有已解决子问题的答案。不管子问题以后是否被用到,只要他被计算过就将其结果填入表中。
证明问题满足贪心选择性质和最优子结构性质
核心代码
m[i][j] = max(m[i-1][j], m[i-1][j-w[i]] + v[i]);
- m[i][j]表示背包容量为j,可选择的物品为前j个物品时,01背包问题的最优值。
- 第i个物品是否加入背包取决于:这个物品的价值 v[i] 加上背包加入该物品后剩余空间能装物品的价值 m[i-1][j-w[i]] 与不加该物品背包空间能装物品的价值 m[i-1][j] 谁大。
- 由于是从第一个物品开始求,所以每个物品不加前的最优解都知道答案。
- traceback()函数中也是通过比较 m[i][j] 与 m[i-1][j] 是否相等来判断第i个物品是否被装进背包。
三、代码
C++
#include <iostream>
using namespace std;
const int N = 1000;
int v[N], w[N], x[N];
int m[N][N];
int c=0, n=0;
void traceback();
int main(){
cin>>n>>c;
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=1;j<=c;j++)
{
if(j>=w[i]){
m[i][j] = max(m[i-1][j], m[i-1][j-w[i]] + v[i]);
}
else
m[i][j] = m[i-1][j];
}
}
traceback();
cout<<"Optimal value is"<<endl;
cout<<m[n][c]<<endl;
for(int i=1;i<n;i++)
cout<<x[i]<<' ';
cout<<x[n]<<endl;
return 0;
}
void traceback(){
int k=c;
for (int i = n; i > 0; i--) {
if(m[i][k] == m[i-1][k])
x[i]=0;
else{
x[i]=1;
k-=w[i];
}
}
}

浙公网安备 33010602011771号