0-1背包问题:
有N件商品和一个容量为V的背包。第 i 件商品的容量为c[i],价值时w[i]。求解将那些物品装入背包可使这些物品的费用总和不超过背包容量, 其价值总和最大。
问题特点:每种物品只有一件,可以选择放或者不放。
算法基本思想
利用动态规划,子问题为:f[i][v]表示前 i 件物品恰恰放入一个(剩余容量)容量为 v 的背包可以获得的最大价值。
其状态转移方程为:f[i][v] = max{ f[i-1][v], f[i-1][v-c[i]] + w[i]}
解释:“将前 i 件商品放入容量为 v 的背包中” 这个子问题,如果只考虑第 i 件商品放或者不放,那么就可以转化为只涉及前 i-1件物品的问题。即 (1)如果不放第 i 件物品,则问题转化为“前 i-1件物品放入容量为v的背包中”;(2)如果放第 i 将物品,则问题转换为 “前 i-1 件物品放入剩下的容量为v-c[i]的背包中”(此时可能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第 i 件物品获得的价值w[i]).则f[i][v]的值就是 (1)(2)中的最大值。
注:f[i][v]有意义当且仅当存在一个前 i 件物品的子集, 其费用总和为v。所以,按照这个方程地推完毕后,最优的答案不一定时f[N][V],而是f[N][0..V]的最大值。
详见http://www.cnblogs.com/zlcxbb/p/5820666.html
代码例子:
#include <iostream>
using namespace std;
//***********************常量定义*****************************
const int MAX_NUM = 3500;
const int MAX_WEIGHT = 14000;
//*********************自定义数据结构*************************
//********************题目描述中的变量************************
int weight[MAX_NUM];
int value[MAX_NUM];
//**********************算法中的变量**************************
//进行空间压缩,使用一维数组
//dp【i】数组存放背包容量为i时,存放的最大价值
//函数从第一个商品开始,一个一个放入背包,并不断修改dp数组的值
int dp[MAX_WEIGHT];
//***********************算法实现*****************************
void Solve( int n, int w )
{
for( int i=1; i<=n; i++ )
{
//因为使用了一维数组,所有j要按照递减顺序
for( int j=w; j>=weight[i]; j-- )
{
if( dp[j-weight[i]] + value[i] > dp[j] )
dp[j] = dp[j-weight[i]] + value[i];
// cout << dp[j] << "j=" << j << "i = " << i << endl;
}
}
cout << dp[w] << endl;
}
//************************main函数****************************
//输入 n 商品个数;背包容量 w
// Weight[i] value[i]
//输出背包容量为 w 时的最大价值
//例如:3 50 10 60 20 100 30 120
//输出 220
int main()
{
//freopen( "in.txt", "r", stdin );
int n, w;
cin >> n >> w; //n为商品个数,w为背包容量
for( int i=1; i<=n; i++ )
{
cin >> weight[i] >> value[i];
}
Solve( n, w );
return 0;
}
0-1背包一维数组实现和二维数组实现的区别:
#include<iostream>
#include <vector>
#include <string.h>
using namespace std;
void oneArray(int n, int w, int weight[], int value[]);
void twoArray(int n, int w, int weight[], int value[]);
int main()
{
int n = 3, w = 50;
int weight[n+1] = {0,10,20,30};
int value[n+1] {0,60,100,120};
// oneArray(n, w, weight, value);
twoArray(n, w, weight, value);
return 0;
}
//一维数组
void oneArray(int n, int w, int weight[], int value[])
{
int dp[w+1] = {0};
for (int i = 1; i <= n; ++i)
{
for (int j = w; j >= weight[i]; --j)
{
if (dp[j-weight[i]] + value[i] > dp[j])
dp[j] = dp[j-weight[i]] + value[i];
}
}
cout << dp[w] << endl;
}
//二维数组
void twoArray(int n, int w, int weight[], int value[])
{
int dp[n+1][w+1] = {0};
memset(dp, 0, sizeof(dp)); //将dp二维数组的值设置成 0
for (int i = 1; i <= n; ++i)
{
for (int j = weight[i]; j <= w; ++j)
{
if (dp[i-1][j-weight[i]] + value[i] > dp[i-1][j])
dp[i][j] = dp[i-1][j-weight[i]] + value[i];
cout << "dp" << i << j << "=" <<dp[i][j];
}
cout <<endl;
}
cout << dp[n][w] << endl;
}