此题只能从上往下挖,可以将每个坑看做一个组,从而转化为分组背包问题,即每组最多取一个物品。
我们将其转化为01背包的思路, d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i i i 组物品在容量为 j j j 的背包中得到的最大价值。由于每组最多之恶能选一个,如果不选,则 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] dp[i][j] = dp[i-1][j-1] dp[i][j]=dp[i−1][j−1]
如果选的话,只能选其中一个,我们需要枚举每一个物品的 w w w 和 v v v, d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − 1 ] [ j − w ] + v ) dp[i][j] = max(dp[i][j], dp[i-1][j-w]+v) dp[i][j]=max(dp[i][j],dp[i−1][j−w]+v)
代码如下:
class Solution {
public:
int maxValueOfCoins(vector<vector<int>>& piles, int k) {
int n = piles.size();
int dp[n+1][k+1]; // dp[i][j]: 前i组物品在容量j的背包下得到的最大价值
memset(dp, 0, sizeof(dp));
// 预处理为前缀和
for(auto& p: piles)
{
for(int i=1;i<p.size();i++)
{
p[i] += p[i-1];
}
}
// 分组背包dp
for(int i=1;i<=n;i++)
{
auto p = piles[i-1];
for(int j=1;j<=k;j++)
{
dp[i][j] = dp[i-1][j];
for(int t=0;t<p.size();t++)
{
int w = t+1, v = p[t];
if(j >= w)dp[i][j] = max(dp[i][j], dp[i-1][j-w]+v);
}
}
}
return dp[n][k];
}
};
同样的,可以压缩到一维,
class Solution {
public:
int maxValueOfCoins(vector<vector<int>>& piles, int k) {
int n = piles.size();
vector<int> dp(k+1); // dp[i][j]: 前i组物品在容量j的背包下得到的最大价值
// 预处理为前缀和
for(auto& p: piles)
{
for(int i=1;i<p.size();i++)
{
p[i] += p[i-1];
}
}
// 分组背包dp
for(int i=1;i<=n;i++)
{
auto p = piles[i-1];
for(int j=k;j>0;j--)
{
for(int t=0;t<p.size();t++)
{
int w = t+1, v = p[t];
if(j >= w)dp[j] = max(dp[j], dp[j-w]+v);
}
}
}
return dp[k];
}
};