鱼C论坛

 找回密码
 立即注册
查看: 1229|回复: 1

[技术交流] 背包九讲

[复制链接]
发表于 2020-3-5 10:17:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 798236606 于 2020-3-5 10:17 编辑

测试平台:https://www.acwing.com/problem/

1.01背包

解:

二维DP

dp[j]表示前i个物品在剩余空间为j的情况下能够装的最大价值量(不一定恰好装满),其中dp[0]必须初始化为0(因为前0个物品的价值量肯定为0)
  1. #include <iostream>
  2. #include <algorithm>

  3. using namespace std;

  4. const int maxn = 1e3 + 10;

  5. int n, m;
  6. int dp[maxn][maxn];

  7. int main(void)
  8. {
  9.     cin >> n >> m;
  10.    
  11.     for (int i = 1; i <= n; ++i)
  12.     {
  13.         int v, w;
  14.         
  15.         cin >> v >> w;
  16.         
  17.         for (int j = 0; j <= m; ++j)//如果装不下,则继承i - 1的结果,若装的下则考虑装与不装哪个更赚
  18.             dp[i][j] = (j < v) ? dp[i - 1][j] : max(dp[i - 1][j], dp[i - 1][j - v] + w);
  19.     }
  20.    
  21.     cout << dp[n][m] << endl;

  22.     return 0;
  23. }
复制代码

【注】大多数一维DP做起来很困难,此时升到二维会简单很多

一维DP

dp[j]表示当前物品与之前的物品(其实还是前i个物品)在剩余空间为j的情况下能够装的最大价值量(不一定恰好装满),其中dp必须初始化为0(因为前0个物品的价值量肯定为0)
  1. #include <iostream>
  2. #include <algorithm>

  3. using namespace std;

  4. const int maxn = 1e3 + 10;

  5. int n, m;
  6. int dp[maxn];

  7. int main(void)
  8. {
  9.     cin >> n >> m;
  10.    
  11.     while (n--)
  12.     {
  13.         int v, w;
  14.         
  15.         cin >> v >> w;

  16.         //装不下的情况不用管,会自然地继承上一次的计算结果,每次计算只是对上次计算的加工处理。j从后往前保证每个物品只被计算一次
  17.         for (int j = m; j >= v; --j) dp[j] = max(dp[j], dp[j - v] + w);
  18.     }
  19.    
  20.     cout << dp[m] << endl;

  21.     return 0;
  22. }
复制代码


2.完全背包

解:
  1. #include <iostream>
  2. #include <algorithm>

  3. using namespace std;

  4. const int maxn = 1e3 + 10;

  5. int n, m;
  6. int dp[maxn];

  7. int main(void)
  8. {
  9.     cin >> n >> m;
  10.    
  11.     while (n--)
  12.     {
  13.         int v, w;
  14.         
  15.         cin >> v >> w;

  16.         //j从前往后保证每个物品可以被计算多次
  17.         for (int j = v; j <= m; ++j) dp[j] = max(dp[j], dp[j - v] + w);
  18.     }
  19.    
  20.     cout << dp[m] << endl;

  21.     return 0;
  22. }
复制代码


其实还有一种更容易想到的解法:枚举每件物品的选取个数(其实把问题转化成了01背包)
  1. #include <iostream>
  2. #include <algorithm>

  3. using namespace std;

  4. const int maxn = 1e3 + 10;

  5. int n, m;
  6. int dp[maxn];

  7. int main(void)
  8. {
  9.     cin >> n >> m;
  10.    
  11.     while (n--)
  12.     {
  13.         int v, w;
  14.         
  15.         cin >> v >> w;

  16.         for (int j = m; j >= v; --j)
  17.             for (int k = 1; k * v <= j; ++k)
  18.                 dp[j] = max(dp[j], dp[j - k * v] + k * w);
  19.     }
  20.    
  21.     cout << dp[m] << endl;

  22.     return 0;
  23. }
复制代码


3.多重背包Ⅰ

解:

类似于上一题的第二种解法
  1. #include <iostream>
  2. #include <algorithm>

  3. using namespace std;

  4. const int maxn = 1e2 + 10;

  5. int n, m;
  6. int dp[maxn];

  7. int main(void)
  8. {
  9.     cin >> n >> m;
  10.    
  11.     while (n--)
  12.     {
  13.         int v, w, t;
  14.         
  15.         cin >> v >> w >> t;

  16.         for (int j = m; j >= v; --j)
  17.             for (int k = 1; k <= t && k * v <= j; ++k)
  18.                 dp[j] = max(dp[j], dp[j - k * v] + k * w);
  19.     }
  20.    
  21.     cout << dp[m] << endl;

  22.     return 0;
  23. }
复制代码

但是当数据较大时效率就会比较差,此时使用二进制优化法

4.多重背包Ⅱ

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>

  4. using namespace std;

  5. const int maxn = 2e3 + 5;

  6. typedef struct GOOD{
  7.     int v, w;
  8.    
  9.     GOOD (int _v, int _w) : v(_v), w(_w) {};
  10. }Good;

  11. int n, m;
  12. int dp[maxn];
  13. vector<Good> goods;

  14. int main(void)
  15. {
  16.     cin >> n >> m;
  17.    
  18.     while (n--)
  19.     {
  20.         int v, w, t;
  21.         
  22.         cin >> v >> w >> t;
  23.         
  24.         for (int k = 1; k <= t; t -= k, k *= 2)
  25.             goods.push_back(GOOD(k * v, k * w));
  26.             
  27.         if (t) goods.push_back(GOOD(t * v, t * w));
  28.     }
  29.    
  30.     for (auto good: goods)
  31.         for (int j = m; j >= good.v; --j)
  32.             dp[j] = max(dp[j], dp[j - good.v] + good.w);
  33.    
  34.     cout << dp[m] << endl;
  35.    
  36.     return 0;
  37. }
复制代码


未完待续。。。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-5 14:55:18 | 显示全部楼层
多谢!
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-4 16:35

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表