01背包详解--模板

点击跳转例题
 

解题:

二维:
1.定义数组: f(i,j)表示前 i个物品,背包容量 j 下的最优解(最大价值)
2.状态转移:f(i,j)可以由什么转移过来,
        (1)当前背包容量不够:(j < v[i]),没得选,因此前 i个物品最优解即为前 i−1 个物品的最优解:f(i,j)=f(i-1,j)
        (2)当前背包容量够:可以选,因此需要决策选与不选第 i个物品:

选:f(i,j)=f(i-1,j-v[i])+w[i];
不选:f(i,j)=f(i-1,j);
最后选与不选取最大值即可;
3.初始化:f(0,0)可以根据定义来决定,值为0。
4.递推:从开始的状态递推到最终的状态。
 

优化为一维:  
1.为什么优化:节约空间,方便书写。
2.为什么可以优化:因为我们转移的时候都是用到了同一层状态,所以我们保证递推的时候从哪一层转移来的不变即可。
3.怎么优化:递推的时候保证从后往前即可,因为要保证:在用 i-1 轮的状态的时候没有使用第 i 轮的状态。
例如,一维状态第 i 轮对体积为 3 的物品进行决策,则f[7]由f[7-3]更新而来,这里的f[4]正确应该是f[i - 1][4],但从小到大枚举到7 的时候 f[4] 在第i轮计算却变成了 f[i][4] 。我们再更新f[7]的时候,就错误了。

如果使用顺序,会先更新f[4],再更新f[7],对于这个书包问题来讲,就是有可能,在更新f[4]的时候,已经把这次能加的物品加进来了,然后更新f[7]的时候,还有可能再加一次,所以必须使用逆序,保证,f[4]是没有加入新物品前,背包里的最优解。

代码:

//dp 思考思路:
//1.状态表示:多积累经验:所有的状态计算及边界 都围绕所表示的状态; 
//2.选择问题:如背包问题:第一维表示物品:后边的维度表示限制;
//状态计算:
//一定要考虑所有情况;求最值可以重复;
//dp:优化;朴素做法,然后对代码做等价变化;思路不能变; 
#include <iostream>
#include <algorithm>

using namespace std;

const int N=1010;
int v[N],w[N];
int f[N][N];//状态表示; 
//前i个物品体积为j的所有方案;
//属性:价值最大值;
//状态转移,选与不选·;
int n,m;

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>v[i]>>w[i];
    }

    //f[0][0~m]表示从0个物品价值0~m的最大值:为0; 
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            //当前背包不能装下第i个物品;价值为i-1的物品价值; 
            if(j<v[i])
            {
                f[i][j]=f[i-1][j];
             } 
             //可以装下,不要上一个物品;
             //还是装这个物品,决策第i个物品;
              //因为每一次都是由上一次而来,所以为表示最大值 
             else //只有一个的时候已经存完了每一个物品的价值;f[1][0~j]; 
             f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]); //优化为一维后f[i-1]要先被计算计算;所以逆序;
             //举个例子:一个物品价值2;另一个价值3;体积都为2;
             //j为3时;f[2][3]=max(f[1][3],f[1][3-2]+w[2]; 
         } 
    cout<<f[n][m];
    return 0;
 } 

一维:
 

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m;
int v[N], w[N];
int f[N];

int main()
{
    cin >> n >> m;

    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];

    for (int i = 1; i <= n; i ++ )//决策每个物品
        for (int j = m; j >= v[i]; j -- )//找每一次决定的最优解;
            f[j] = max(f[j], f[j - v[i]] + w[i]);

    cout << f[m] << endl;

    return 0;
}

  • 18
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值