徹底揹包變型題(hdu5410)

這是2015年最後一場多校的dp題,當時只怪本身基礎太差,想了1個多小時纔想出來,哎,9月份好好鞏固基礎,爲區域賽作準備。題目傳送門php

題目的意思是給你n元錢,m類糖果,每類糖果分別有p, a, b, p表示單價,假設付了w*p元,那麼他能得到a*w + b個糖果。求最大的糖果數。數組

當時一看到這題,以爲是徹底揹包,設dp[i][j]表示買到第i件物品的時候已經花了j元錢,所獲得的最多的糖果數。ide

很容易想到轉移方程爲:優化

dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - k * p] + a * k + b);(k > 0 && k * p <= j)spa

當信心十足準備敲的時候才突然發現時間複雜度爲O(n^3), 而n 最大爲1000,毫無疑問會超時。怎麼辦?3d

而後咱們就想咱們用01揹包的思惟去想這題,就能夠把它優化到O(n^2)了;而後忽然又發現一個問題,由於多了個b,發現處理的時候要考慮是不是第一次買,那麼咱們就開個vis數組來表示有無買過,1表示買過,0表示沒有。code

附上總代碼:blog

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int N = 2000 + 5;
 7 
 8 int T, n, m;
 9 
10 int p[N], a[N], b[N];
11 
12 int vis[N][N], dp[N][N];
13 
14 void work(){
15     memset(dp, 0, sizeof(dp));
16     memset(vis, 0, sizeof(vis));
17     for(int i = 1; i <= n; i ++){
18         for(int j = 0; j <= m; j ++){
19             dp[i][j] = dp[i - 1][j];
20             if(j >= p[i]){
21                 int t = dp[i][j - p[i]] + a[i];
22                 if(!vis[i][j - p[i]]) t += b[i];
23                 int t1 = dp[i - 1][j - p[i]] + a[i] + b[i];
24                 if(t1 > t) t = t1;
25                 if(t > dp[i][j]){
26                     dp[i][j] = t;
27                     vis[i][j] = 1;
28                 }
29             }
30         }
31     }
32     printf("%d\n", dp[n][m]);
33 }
34 
35 int main(){
36     scanf("%d", &T);
37     while(T--){
38         scanf("%d%d", &m, &n);
39         for(int i = 1; i <= n; i ++) scanf("%d%d%d", p + i, a + i, b + i);
40         work();
41     }
42     return 0;
43 }
View Code
相關文章
相關標籤/搜索