1. 程式人生 > >【bzoj4247】掛飾 背包dp

【bzoj4247】掛飾 背包dp

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