Luogu P2297 刷图 DP
题目背景
loidc,LOI中的传说级哲♂学家,曾经创造一天内入坑maxlongint个弃坑0x7fffffff个的神奇纪录。目前,loidc最喜欢的游戏就是地下城与勇♂士。
题目描述
Loidc是一个勤奋的孩子。 他每天都会勤奋的搬砖刷疲劳,每天都会期待着各种BOSS给他爆点什么神奇的东西(例如魔剑..),但是每次刷远古总会坑到连门票钱也赚不回来。 最近loidc新技能get√ 他每天都会朗诵一遍线段树,将自己升级为”Deep Dark Fantasy”模式(其实是每天去给腾讯爹送钱)下才去搬砖,所以他人品次次爆发,每次刷图后腾讯都会象征性给他爆点好东西。 今天他又来刷一个叫做“痛苦之村列瑟芬”的图,每次刷完图后都会有N个掉落物。但是loidc很健忘,他每次都会忘清空背包,所以不一定是所有东西都能带回去。 i个物品有两个属性A_i和B_i,现在loidc需要在其中选取若干个物品,使得sum{A_i + B_i}最大,同时sum{A_i},sum{B_i}均非负。但是由于loidc太弱,所以这个工作交给了你。
输入输出格式
输入格式:第一行,一个整数,表示掉落物个数N。 接下来N行,每行两个整数,表示A_i和B_i。
输出格式:一个整数,表示最大的sum{A_i + B_i}。
输入输出样例
5 -5 7 8 -6 6 -3 2 1 -8 -5
8
说明
N <= 100 , |A_i| <= 1000 , |B_i| <= 1000 sum{}表示求和
LuoguP2340 奶牛会展 双倍经验爽!!
提交地址 : https://www.luogu.org/problemnew/show/P2297#sub
and https://www.luogu.org/problemnew/show/P2340#sub
分析:
裸裸的01背包吗。
把属性a当做体积, 属性b当做价值;
妥妥的ok;
但有个小问题,数组并不能存负值;
所以要平移数组,最后就是裸背包;
然后枚举移动的位数,判断b属性大于零,然后 取max;
代码:
// By zZhBr #include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; int n; int m; int a[110], b[110]; int dp[110001]; int ans; int main() { cin >> n; for(register int i = 1 ; i <= n ; i ++) { scanf("%d%d", &a[i], &b[i]); m += a[i] > 0 ? a[i] : 0; } memset(dp, 0xcf, sizeof dp); m *= 2; dp[m/2] = 0; for(register int i = 1 ; i <= n ; i ++) { if(a[i] > 0) { for(register int j = m ; j >= a[i] ; j --) { dp[j] = max(dp[j], dp[j-a[i]] + b[i]); } } else { for(register int j = 0 ; j <= m - a[i] ; j ++) { dp[j] = max(dp[j], dp[j-a[i]] + b[i]); } } } int k = m / 2; for(register int i = 1 ; i <= k ; i ++) { if(dp[i+k] >= 0) { ans = max(ans, i + dp[i+k]); } } printf("%d\n", ans); return 0; }