习题:刷图(01背包)
洛谷2297
题目描述
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}。
输入输出样例
输入样例#1:
5
-5 7
8 -6
6 -3
2 1
-8 -5
输出样例#1:
8
说明
N <= 100 , |A_i| <= 1000 , |B_i| <= 1000
sum{}表示求和
分析:
用f[i,j]表示sum(ai)=i时sum(bi)的最大值。
这样就变成01背包了
但注意因为有负数,要分情况转移。
代码:
program hehe; var a,b:array[0..100]of longint; f:array[-100000..100000]of longint; n,i,m,j,ans,v:longint; function max(x,y:longint):longint; begin if x>y then max:=x else max:=y; end; begin readln(n); for i:=1 to n do begin readln(a[i],b[i]); if a[i]<0 then v:=v+a[i] else m:=m+a[i]; end; f[0]:=0; for i:=1 to m do f[i]:=-maxlongint div 3; for i:=1 to n do if a[i]>=0 then begin for j:=m downto v+a[i] do f[j]:=max(f[j],f[j-a[i]]+b[i]); end else begin for j:=v to m+a[i] do f[j]:=max(f[j],f[j-a[i]]+b[i]); end; for i:=0 to m do if f[i]>=0 then begin ans:=max(f[i]+i,ans); end; writeln(ans); end.