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

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值