zoukankan      html  css  js  c++  java
  • hdu5410 CRB and His Birthday

    本题其实是经典(完全)背包问题的一个变种,只不过需要处理一下B[i]。

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

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

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

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

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

    1 int solve(){
    2   for(int i = 0; ; i++){
    3     int k = i % n;
    4     for(int j = m; j >= W[k]; j--){
    5       dp[j] = max(dp[j], dp[j -W[i]] + A[k] + (i < n ? B[k] : 0));
    6     }
    7   }
    8   return ans = dp[m];
    9 }

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

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

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

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

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

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

    这样就可得出答案了。

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

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

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 
     5 using namespace std;
     6 
     7 const int maxn = 1e3 + 10;
     8 int dp[maxn * 2];
     9 int w[maxn], a[maxn], b[maxn];
    10 int n, m;
    11 
    12 void solve(){
    13     memset(dp, 0, sizeof dp);
    14     //preprocessing:: 0-1 packing
    15     for(int i = 0; i < n; i++){
    16         for(int j = m; j >= w[i]; j--){
    17             dp[j] = max(dp[j], dp[j - w[i]] + a[i] + b[i]);
    18         }
    19     }
    20     //full packing
    21     for(int i = 1; i <= m; i++){
    22         for(int j = 0; j < n; j++){
    23             if(i >= w[j]) dp[i] = max(dp[i - w[j]] + a[j], dp[i]);
    24         }
    25     }
    26     /*
    27     for(int i = 0; i < n; i++){
    28         for(int j = w[i]; j <= m; j++){
    29             dp[j] = max(dp[j], dp[j - w[i]] + a[i]);
    30         }
    31     }
    32     */
    33     printf("%d
    ", dp[m]);
    34 }
    35 
    36 int main(){
    37     //freopen("in.txt", "r", stdin);
    38     int T;
    39     scanf("%d", &T);
    40     while(T--){
    41         scanf("%d%d", &m, &n);
    42         for(int i = 0; i < n; i++) scanf("%d%d%d", &w[i], &a[i], &b[i]);
    43         solve();
    44     }
    45     return 0;
    46 }
    View Code

     

  • 相关阅读:
    自解代理模式
    顺时针打印二维方阵
    Dom4j官网解释实例
    Eclipse快捷键大全
    MyEclipse快捷键大全
    SQL语句的增删改查(详细)
    MySQL用户权限详细汇总
    从表中随机返回n条记录
    证件照(1寸2寸)拍摄处理知识汇总
    java 实现文件内容的加密和解密
  • 原文地址:https://www.cnblogs.com/astoninfer/p/4749051.html
Copyright © 2011-2022 走看看