返回
妙不可言,一题10000种情况,只要你想得到的,它就有
人工智能
2023-10-18 20:56:00
引言
哈喽大家好,今天我们来唠唠codeforces 1425场比赛的E题。这道题的难度被评为Medium,全场只有157人通过。对于难度为Medium的题来说,通过率这么低,是不是有点太不给力了呢?
题目
这道题的题目是这样的:
给定一个物品集合,每个物品都有自己的价值和重量。现在需要从这个物品集合中选出一些物品,使得它们的总价值最大,同时总重量不超过背包的容量。
其中,每个物品可以被选择多次,但是每次只能选择一个。
乍一看,这道题是不是和背包问题很像?没错,这道题就是背包问题的变形,称为多重背包问题。
解题思路
对于多重背包问题,我们可以使用动态规划来解决。动态规划的思想是将问题分解成若干个子问题,然后逐个解决这些子问题,最后将子问题的解组合起来得到原问题的解。
对于这道题,我们可以定义状态dp[i][j]
,表示前i
个物品放入容量为j
的背包中的最大价值。
根据动态规划的思想,我们可以得到状态转移方程:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])
其中,w[i]
和v[i]
分别表示第i
个物品的重量和价值。
为了优化空间复杂度,我们可以使用状态压缩的思想。状态压缩的思想是将状态用二进制数表示,这样就可以用一个整数来表示多个状态。
对于这道题,我们可以将容量j
用二进制数表示,这样就可以用一个整数来表示所有容量为j
的状态。
代码实现
使用状态压缩后的代码如下:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1010;
const int MAXW = 1010;
int n, m;
int w[MAXN], v[MAXN];
int dp[(1<<MAXW)];
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 = (1<<MAXW)-1; j >= w[i]; j--) {
dp[j] = max(dp[j], dp[j-w[i]] + v[i]);
}
}
cout << dp[(1<<MAXW)-1] << endl;
return 0;
}
总结
这道题的难度并不大,但是由于是多重背包问题,所以需要用到动态规划和状态压缩的思想。掌握了这些思想,我们就可以解决这类问题。
希望这篇文章对大家有所帮助,感谢阅读!