|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 798236606 于 2020-3-5 10:17 编辑
测试平台:https://www.acwing.com/problem/
1.01背包
解:
二维DP
dp[j]表示前i个物品在剩余空间为j的情况下能够装的最大价值量(不一定恰好装满),其中dp[0]必须初始化为0(因为前0个物品的价值量肯定为0)
- #include <iostream>
- #include <algorithm>
- using namespace std;
- const int maxn = 1e3 + 10;
- int n, m;
- int dp[maxn][maxn];
- int main(void)
- {
- cin >> n >> m;
-
- for (int i = 1; i <= n; ++i)
- {
- int v, w;
-
- cin >> v >> w;
-
- for (int j = 0; j <= m; ++j)//如果装不下,则继承i - 1的结果,若装的下则考虑装与不装哪个更赚
- dp[i][j] = (j < v) ? dp[i - 1][j] : max(dp[i - 1][j], dp[i - 1][j - v] + w);
- }
-
- cout << dp[n][m] << endl;
- return 0;
- }
复制代码
【注】大多数一维DP做起来很困难,此时升到二维会简单很多
一维DP
dp[j]表示当前物品与之前的物品(其实还是前i个物品)在剩余空间为j的情况下能够装的最大价值量(不一定恰好装满),其中dp必须初始化为0(因为前0个物品的价值量肯定为0)
- #include <iostream>
- #include <algorithm>
- using namespace std;
- const int maxn = 1e3 + 10;
- int n, m;
- int dp[maxn];
- int main(void)
- {
- cin >> n >> m;
-
- while (n--)
- {
- int v, w;
-
- cin >> v >> w;
- //装不下的情况不用管,会自然地继承上一次的计算结果,每次计算只是对上次计算的加工处理。j从后往前保证每个物品只被计算一次
- for (int j = m; j >= v; --j) dp[j] = max(dp[j], dp[j - v] + w);
- }
-
- cout << dp[m] << endl;
- return 0;
- }
复制代码
2.完全背包
解:
- #include <iostream>
- #include <algorithm>
- using namespace std;
- const int maxn = 1e3 + 10;
- int n, m;
- int dp[maxn];
- int main(void)
- {
- cin >> n >> m;
-
- while (n--)
- {
- int v, w;
-
- cin >> v >> w;
- //j从前往后保证每个物品可以被计算多次
- for (int j = v; j <= m; ++j) dp[j] = max(dp[j], dp[j - v] + w);
- }
-
- cout << dp[m] << endl;
- return 0;
- }
复制代码
其实还有一种更容易想到的解法:枚举每件物品的选取个数(其实把问题转化成了01背包)
- #include <iostream>
- #include <algorithm>
- using namespace std;
- const int maxn = 1e3 + 10;
- int n, m;
- int dp[maxn];
- int main(void)
- {
- cin >> n >> m;
-
- while (n--)
- {
- int v, w;
-
- cin >> v >> w;
- for (int j = m; j >= v; --j)
- for (int k = 1; k * v <= j; ++k)
- dp[j] = max(dp[j], dp[j - k * v] + k * w);
- }
-
- cout << dp[m] << endl;
- return 0;
- }
复制代码
3.多重背包Ⅰ
解:
类似于上一题的第二种解法
- #include <iostream>
- #include <algorithm>
- using namespace std;
- const int maxn = 1e2 + 10;
- int n, m;
- int dp[maxn];
- int main(void)
- {
- cin >> n >> m;
-
- while (n--)
- {
- int v, w, t;
-
- cin >> v >> w >> t;
- for (int j = m; j >= v; --j)
- for (int k = 1; k <= t && k * v <= j; ++k)
- dp[j] = max(dp[j], dp[j - k * v] + k * w);
- }
-
- cout << dp[m] << endl;
- return 0;
- }
复制代码
但是当数据较大时效率就会比较差,此时使用二进制优化法
4.多重背包Ⅱ
- #include <iostream>
- #include <vector>
- #include <algorithm>
- using namespace std;
- const int maxn = 2e3 + 5;
- typedef struct GOOD{
- int v, w;
-
- GOOD (int _v, int _w) : v(_v), w(_w) {};
- }Good;
- int n, m;
- int dp[maxn];
- vector<Good> goods;
- int main(void)
- {
- cin >> n >> m;
-
- while (n--)
- {
- int v, w, t;
-
- cin >> v >> w >> t;
-
- for (int k = 1; k <= t; t -= k, k *= 2)
- goods.push_back(GOOD(k * v, k * w));
-
- if (t) goods.push_back(GOOD(t * v, t * w));
- }
-
- for (auto good: goods)
- for (int j = m; j >= good.v; --j)
- dp[j] = max(dp[j], dp[j - good.v] + good.w);
-
- cout << dp[m] << endl;
-
- return 0;
- }
复制代码
未完待续。。。 |
|