动态规划之01-背包问题

动态规划的⼀般流程就是三步:暴⼒的递归解法 -> 带备忘录的 递归解法 -> 迭代的动态规划解法。 就思考流程来说,就分为⼀下⼏步:找到状态和选择 -> 明确 dp 数组/函数 的定义 -> 寻找状态之间的关系。

动态规划问题的⼀般形式就是求最值。动态规划其实是运筹学的⼀种最优化 ⽅法,只不过在计算机问题上应⽤⽐较多,⽐如说让你求最⻓递增⼦序列 呀,最⼩编辑距离呀等等。 既然是要求最值,核⼼问题是什么呢?求解动态规划的核⼼问题是穷举

动态规划问题⼀定会具备最优⼦结构。

最优⼦结构:原问题的最优解包含子问题的最优解。

递推实现动态规划的缺点:在循环中会计算非子问题的最优解(多余的计算)。

递推实现动态规划的优点:免去了递归调用时的进出栈操作递归层数过多时,会栈溢出。

虽然动态规划的核⼼思想就是穷举求最值,但是问题可以千变万化, 穷举所有可⾏解其实并不是⼀件容易的事,只有列出正确的「状态转移⽅ 程」才能正确地穷举。

辅助你思考状态转移⽅程: 明确「状态」 -> 定义 dp 数组/函数的含义 -> 明确「选择」-> 明确 base case。

0-1背包问题

0-1背包问题是动态规划常见问题之一;

有n个物品,它们有各自的体积和价值,第i种物品的体积为Vi,现有给定容量为C的背包,如何让背包里装入的物品具有最大的价值总和?1<=n<=100,1<=Vi<=C<=10000,1<=Wi<=10^6.

 

包的容量比该商品体积小,装不下,此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j);
还有足够的容量可以装该商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即d(i,j)=max{d(i-1,j),d(i-1,j-V(i))+W(i)},d(i,j)=0,j<0是负无穷。
其中V(i-1,j)表示不装,V(i-1,j-w(i))+v(i) 表示装了第i个商品,背包容量减少w(i),但价值增加了v(i);

由此可以得出递推关系式:

j<w(i)      V(i,j)=V(i-1,j)
j>=w(i)     V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}

 i必须逆序枚举,但j的循环次序是无关的。

规划方向:f(i,j)=max{f(i-1,j),f(i-1,j-V[i])+W[i]}


#include <iostream>
#include <cstring>
using namespace std;

const int N = 1010;

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

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

    for (int i = 1; i <= n; i ++ )
        for (int j = 0; j <= m; j ++ )
        {
            f[i][j] = f[i - 1][j];
            if (j >= w[i]) f[i][j] = max(f[i][j], f[i - 1][j - w[i]] + v[i]);
        }

    cout << f[n][m] << endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值