0-1背包问题

内容会持续更新,有错误的地方欢迎指正,谢谢!

问题

有 N 件物品和一个容量为 V 的背包。第 i 件物品的体积是 Ci,其价值是 Wi。求在不超过背包容量V的情况下,将哪些物品装入背包可使价值总和最大。

思路

很明显的一道考察动态规划的题目。
F(i,V)表示 在前i件商品中选择若干件放入容量为V的背包中,可获得的最大价值。
递推式:
1. 如果i等于0,F(i,V)=0
2. 如果i大于0,F(i,V)=max{F(i-1,V),F(i-1,V-Ci)+Wi}
即对于第i件物品,有要与不要两种选择:如果不要,F(i,V)=F(i-1,V);如果要,那就先判断V-Ci是否>=0确保有没有足够的空间,如果没有那就还是不要,如果有那就要F(i,V)=F(i-1,V-Ci)+Wi。

代码

//递归实现
#include <iostream>
using namespace std;
int C[5]={5,1,4,2,1};//每个物品的体积
int W[5]={4,1,5,4,2};//每个物品的价值
int MaxValue(int i,int V)
{
    if(i==0||V==0)//没有物品可选或体积为0时
        return 0;
    int doChoose=-1;
    if(V-C[i-1]>=0)//i的取值范围为[1,6],所以要减一
        doChoose=MaxValue(i-1,V-C[i-1])+W[i-1];
    int notChoose=MaxValue(i-1,V);
    return (doChoose>notChoose)?doChoose:notChoose;
}
int main()
{
    int N=5;//物品的件数
    int V=8;//背包的体积
    cout << MaxValue(N,V) << endl;
    return 0;
}

//迭代实现,F这个二维数组就是 价值F(i,V) 的表格,最右下角的元素为最大价值。
#include <iostream>
using namespace std;
int main()
{
    const int N = 6;//物品个数
    const int V = 10;//背包体积
    int C[N+1] = {0,5,1,4,2,1};//每个物品的体积,下标从1开始
    int W[N+1] = {0,4,1,5,4,2};//每个物品的价值
    int F[N + 1][V + 1] = { 0 };//全部初始化为0,用于记录状态
    for (int i = 1; i <= N; i++)//对于第 i 个物品
        for (int v = 0; v <= V; v++)
        {
            F[i][v] = F[i - 1][v];//第i个不放
            //如果放了第i个,比它大的话,就放第i个
            if (v - C[i] >= 0 && F[i][v] < F[i - 1][v - C[i]] + W[i])
                F[i][v] = F[i - 1][v - C[i]] + W[i];
        }
    cout << "最大价值是:" << F[N][V] << endl;
    return 0;
}

复杂度分析及优化

对于迭代这个方法来说,时间和空间复杂度均为 O(VN),其中时间复杂度应该已经不能再优化了,但空间复杂度却可以优化到 O(V)。

以v递减顺序计算 F[v],这样才能保证计算 F[v] 时 F[v−Ci] 保存的是状态F[i−1,v−Ci] 的值。

//了解就好
#include <iostream>
using namespace std;
int main()
{
    const int N = 6;//物品个数
    const int V = 8;//背包体积
    int C[N+1] = {0,5,1,4,2,1};//每个物品的体积,下标从1开始
    int W[N+1] = {0,4,1,5,4,2};//每个物品的价值
    int F[V + 1] = { 0 };
    for (int i = 1; i <= N; i++)//对于第 i 个物品
        for (int v = V; v-C[i]>=0; v--)
            F[v]=max(F[v],F[v-C[i]]+W[i]);
    cout << "最大价值是:" << F[V] << endl;
    return 0;
}

如上,空间复杂度便得到了优化,变成了O(V)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值