背包问题,动态规划经典问题,几个不同价值和权重的物品,一个给定满权重的背包,求装满背包权重所能获得的最大价值。
01背包问题
题目:一个绿茶有很多的舔狗,她为了维持女神形象,对微信的最大回复流量为4(超过就会CPU过载,发消息串流,被发现是海王),现在舔狗1号小王(想你的夜)发送消息的流量是1,绿茶能从其获得的价值是15,舔狗2号小李(pc被抓)发送消息的流量是3,绿茶能从其获得的价值是20,舔狗3号小吴(我大你忍)发送消息的流量是4,绿茶能从其获得的价值是30,现在你的女神为了养鱼不被发现,请你帮忙计算一下,怎么能在不串流的情况下选择合适的舔狗获得最大的价值。
首先考虑暴力的解法
最朴素的解法,暴力枚举。由排列组合计算所有的可能性
只选一个人
1号 流量 1 价值15 y
2号 流量 3 价值20 y
3号 流量 4 价值30 y
选两个人
1和2 流量 4 价值 35 y
1和3 流量 5 价值 45 n
2和4 流量 7 价值 50 n
三个人
1,2,3 流量8 价值 65 n
显然,由枚举能获得的最大流量为35,其余的超过绿茶能把握的最大流量。
优化 从占据流量最大的人开始
仅仅有3号时 流量是4 ,最大价值为 30 流量为4时的最大价值更新为30
当2号加入 流量是4 ,流量是3号的4 价值是3号的30 ,
要么流量是2号的3 价值是2号的20
能把握的最大为价值为30 ,流量为4
当1号加入,查询4号,此时,4号此时的最大流量为30,遍历到2号时,发现二号距离最大的流量还有1个流量,所以去查流量为1时所能获得的价值,此时流量1的价值为15,故15+20>30,流量为4时更新。
故代码中,dp数组,其下标含义为,此时流量为i时,所能获得的最大价值。
代码
#include <climits>
#include <iostream>
#include <vector>
using namespace std;
// 计算在给定权重限制下能获得的最大物品价值
void max_value_with_weight_limit()
{
vector<vector<int>> v_list = {{1, 15}, {3, 20}, {4, 30}};
int power = 4;
vector<int> f1(power + 1, 0);
for (auto& rtn : v_list)
{
//从后向前更新
for (int j = power; j >= rtn[0]; --j) // 从power递减到rtn[0]
{
f1[j] = max(f1[j], f1[j-rtn[0]] + rtn[1]); // 更新价值
}
}
cout << f1[power] << "\n"; // 输出最大价值
}
int main()
{
max_value_with_weight_limit();
return 0;
}
留下的问题,思考:为什么要从后往前更新?从前向后更新呢?
todo!