【bzoj4247】掛飾 背包dp
阿新 • • 發佈:2017-06-25
sizeof 輸出 負數 ems 描述 max ring div 分隔
輸出一行一個整數,表示手機上連接的掛飾總和的最大值
題目描述
JOI君有N個裝在手機上的掛飾,編號為1...N。 JOI君可以將其中的一些裝在手機上。 JOI君的掛飾有一些與眾不同——其中的一些掛飾附有可以掛其他掛件的掛鉤。每個掛件要麽直接掛在手機上,要麽掛在其他掛件的掛鉤上。直接掛在手機上的掛件最多有1個。 此外,每個掛件有一個安裝時會獲得的喜悅值,用一個整數來表示。如果JOI君很討厭某個掛飾,那麽這個掛飾的喜悅值就是一個負數。 JOI君想要最大化所有掛飾的喜悅值之和。註意不必要將所有的掛鉤都掛上掛飾,而且一個都不掛也是可以的。輸入
第一行一個整數N,代表掛飾的個數。 接下來N行,第i行(1<=i<=N)有兩個空格分隔的整數Ai和Bi,表示掛飾i有Ai個掛鉤,安裝後會獲得Bi的喜悅值。輸出
樣例輸入
5
0 4
2 -2
1 -1
0 1
0 3
樣例輸出
5
題解
背包dp
根據題意很容易想到dp狀態:f[i][j]表示從前i個物品中選擇某些物品,使得剩下的掛鉤數量為j的最大喜悅值。
但是這樣會TLE。
思考:一個物品,最多只會消耗1個掛鉤。因此如果已經有了大於等於超過n個掛鉤,說明全部物品都可以掛上,記錄過多的狀態也就沒有了意義。
所以我們把j的上界設為n即可,dp時取j+ai和n的最小值作為狀態即可。
註意要先按照掛鉤數量從大到小排序(其實不排序也行,就是會比較麻煩)
代碼中把狀態壓到了一維,需要註意一下更新順序啥的。
#include <cstdio> #include <cstring> #include <algorithm> #define N 2010 using namespace std; struct data { int a , b; }w[N]; int f[N]; bool cmp(data x , data y) { return x.a > y.a; } int main() { int n , i , j , ans = 0; scanf("%d" , &n); for(i = 1 ; i <= n ; i ++ ) scanf("%d%d" , &w[i].a , &w[i].b) , w[i].a -- ; sort(w + 1 , w + n + 1 , cmp); memset(f , 0xc0 , sizeof(f)) , f[1] = 0; for(i = 1 ; i <= n ; i ++ ) { if(~w[i].a) for(j = n ; j ; j -- ) f[min(j + w[i].a , n)] = max(f[min(j + w[i].a , n)] , f[j] + w[i].b); else for(j = 1 ; j <= n ; j ++ ) f[j - 1] = max(f[j - 1] , f[j] + w[i].b); for(j = 0 ; j <= n ; j ++ ) ans = max(ans , f[j]); } printf("%d\n" , ans); return 0; }
【bzoj4247】掛飾 背包dp