返回

妙不可言,一题10000种情况,只要你想得到的,它就有

人工智能

引言

哈喽大家好,今天我们来唠唠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;
}

总结

这道题的难度并不大,但是由于是多重背包问题,所以需要用到动态规划和状态压缩的思想。掌握了这些思想,我们就可以解决这类问题。

希望这篇文章对大家有所帮助,感谢阅读!