hdu 5410 CRB and His Birthday(01背包+完全背包)

题目链接:

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

解题思路:

官方题解:

We use dynamic programming to get optimal solution.

Presents with same prices can be considered in groups.

In each group, it is needed to get the maximum number of candies that can be got when k presents are bought.

We sort the presents in non-increasing order of Ai+BiAi+Bi.

Let MAMA be the maximum of AiAitt be the minimum of index ii which satisfies inequality Ai+Bi<MAAi+Bi<MA.

We use following strategy.

If k\ <\ tk < t, then for every index from 1 to kk, buy one of that kind and get (A1+B1)+...+(Ak+Bk)(A1+B1)+...+(Ak+Bk) candies.

Else we buy one present for each index\in[1...tt] and (k-t)(kt) presents of that kind whose AA value equals MAMA. In this case we get (A1+B1)+...+(At+Bt)+(k-t)MA(A1+B1)+...+(At+Bt)+(kt)MA candies.

Let dp[n][m]dp[n][m] be the optimal value we can get passing through nn groups with mm Won.

dp[n][m]\ =\ max(dp[n-1][m-k\times\ w[n]]\ +\ opt[n][k])\ (0\ \leq \ k\ \leq \ m / w[n])dp[n][m] = max(dp[n1][mk× w[n]] + opt[n][k]) (0  k  m/w[n]).

(opt[n][k]opt[n][k]: the maximum number of candies we can get when we buy kk presents of nn-th group, w[n]w[n]: the price for nn-th group)

Time complexity:O(N\times \ (M/1\ +\ M/2\ +...+\ M/M))\ =\ O(NM\cdot logM)O(N× (M/1 + M/2 +...+ M/M)) = O(NMlogM)

首先考虑b[i]存在的情况,b[i]只会出现在第一次购买商品的时候用上,用01背包处理,然后01背包处理完后,接着跑一遍多重背包,这次仅考虑a[i]对最终结果的影响,最终输出dp[m]即为最终结果。
为什么可以这样呢?因为01背包仅仅是考虑第一次买的情况,在01背包之后跑多重背包,状态是建立在01背包的基础之上,而这正是我们需要的状态。。。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int dp[2005];
int val[1005];
int a[1005],b[1005];

int main(){
    int T;
    int n,m;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&m,&n);
        memset(dp,0,sizeof(dp));
        for(int i = 1; i <= n; i++)
            scanf("%d%d%d",&val[i],&a[i],&b[i]);
        for(int i = 1; i <= n; i++)
            for(int j = m; j >= val[i]; j--)
                dp[j] = max(dp[j],dp[j-val[i]]+a[i]+b[i]);
        for(int i = 1; i <= n; i++)
            for(int j = val[i]; j <= m; j++)
                dp[j] = max(dp[j],dp[j-val[i]]+a[i]);
        printf("%d\n",dp[m]);
    }
    return 0;
}


你可能感兴趣的:(01背包,完全背包)