0-1 背包问题——动态规划

来源:互联网 发布:本机mac地址怎么查 编辑:程序博客网 时间:2024/06/04 22:46

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//输出 220int 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;}