[JOISC2014]挂饰

[JOISC2014]挂饰
难度:提高+/省选-
分类:动态规划,01背包,贪心,剪枝
分析:初看这道动态规划题,可以看出是一道01背包题,但这道题不同于其他01背包的地方在于挂钩的问题,其挂钩数量如果少于后面挂饰挂钩的数量,便会多次挂上却没有意义,于是我们可以设置一个结构体,将结构体按照挂钩数量从大到小排序,保证先算挂钩数量多的,让后按照01背包模板打上去就可以了,但要注意下表小于0的情况,就把这个挂件扔到手机上就行了,于是可得转移方程:
dp[i][j] = max(dp[i - 1][j],dp[i - 1][max(j - c[i].a,0) + 1] + c[i].b)
注意要先将dp数组赋为极小值,起始状态为dp[0][1] = 0
目标:max(dp[n][i])

code

#include 
#include 
#include 
using namespace std;
int n,dp[5][2005],ans;//可用滚动数组优化
struct node{
	int a,b;//a表示挂钩数量,b表示喜悦值
}c[2005];
bool cmp(const node &x,const node &y) {
	return x.a > y.a;//按照挂钩数量从小到大排序
}
int main() {
	scanf("%d",&n);
	for(int i = 1;i <= n;i ++)
	scanf("%d %d",&c[i].a,&c[i].b);
	sort(c + 1,c + n + 1,cmp);
	memset(dp,-0x3f3f3f3f,sizeof(dp));//极小值
	dp[0][1] = 0;//初始状态
	for(int i = 1;i <= n;i ++) {
		for(int j = 0;j <= n;j ++) {
			dp[i & 1][j] = max(dp[(i - 1) & 1][j],dp[(i - 1) & 1][max(j - c[i].a,0) + 1] + c[i].b);//dp方程
		}
	}
	ans = -0x3f3f3f3f;
	for(int i = 0;i <= n;i ++)
	ans = max(ans,dp[n & 1][i]);//答案
	printf("%d\n",ans);
	return 0;
}

你可能感兴趣的:(DP)