习题:刷图(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.
View Code

 

posted @ 2016-11-13 18:12  QTY_YTQ  阅读(324)  评论(0编辑  收藏  举报