[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 <cstdio>
#include <algorithm>
#include <cstring>
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;
}