您的位置:首页 > 其它

hdu5410 CRB and His Birthday

2015-08-21 21:13 288 查看
本题其实是经典(完全)背包问题的一个变种,只不过需要处理一下B[i]。

设dp[i]为花费i所得糖果最大值。

根据题目,共有n堆礼物,买k个第i堆礼物获得糖果A[i] * k + B[i] (k > 0),每堆礼物数不限。

我们可以把每一堆礼物中的每一个礼物单独看成一堆。那么一共有无穷堆共k组礼物。

belong[i] = i % n代表现在的第i堆糖果原来属于哪一堆。

这样理论上下面的代码可以求解:

int solve(){
  for(int i = 0; ; i++){
    int k = i % n;
    for(int j = m; j >= W[k]; j--){
      dp[j] = max(dp[j], dp[j -W[i]] + A[k] + (i < n ? B[k] : 0));
    }
  }
  return ans = dp[m];
}


这个应该比较直观,容易理解。

那么下面把这个循环改成两部分。

第一部分单独考虑取第一轮dp(原来每堆糖果各拿出一个)。

for(int i = 0; i < n; i++){
  for(int j = m; j >= W[i]; j--){
    dp[i] = max(dp[j], dp[j - W[i]] + A[i] + B[i]);
  }
}


第二部分仍然是完全背包。

for(int i = 1; i <= m; i++){
  for(int j = 0; j < n; j++){
    if(i >= W[j]) dp[i] = max(dp[i], dp[i - W[j]] + A[j]);
  }
}


这样就可得出答案了。

代码中的第二轮循环后面注释代码也是可行的。

acm.hdu.edu.cn/showproblem.php?pid=5410

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 1e3 + 10;
int dp[maxn * 2];
int w[maxn], a[maxn], b[maxn];
int n, m;

void solve(){
memset(dp, 0, sizeof dp);
//preprocessing:: 0-1 packing
for(int i = 0; i < n; i++){
for(int j = m; j >= w[i]; j--){
dp[j] = max(dp[j], dp[j - w[i]] + a[i] + b[i]);
}
}
//full packing
for(int i = 1; i <= m; i++){
for(int j = 0; j < n; j++){
if(i >= w[j]) dp[i] = max(dp[i - w[j]] + a[j], dp[i]);
}
}
/*
for(int i = 0; i < n; i++){
for(int j = w[i]; j <= m; j++){
dp[j] = max(dp[j], dp[j - w[i]] + a[i]);
}
}
*/
printf("%d\n", dp[m]);
}

int main(){
//freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &m, &n);
for(int i = 0; i < n; i++) scanf("%d%d%d", &w[i], &a[i], &b[i]);
solve();
}
return 0;
}


View Code

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: