#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MID(x,y) ((x+y)>>1)
using namespace std;
typedef long long LL;
int f[201010];
int si[110],fi[110];
int main(){
int n;
int inf = - (1 << 30);
scanf("%d", &n);
for (int i = 0; i < n; i ++)
scanf("%d%d", &si[i], &fi[i]);
for (int i = 0; i < 201010; i ++)
f[i] = inf;
f[100000] = 0;
for (int i = 0; i < n; i ++)
if (si[i] < 0 && fi[i] < 0)
continue;
else if (si[i] > 0)
for (int j = 200000; j >= si[i]; j --)
if (f[j - si[i]] > inf)
f[j] = max(f[j], f[j - si[i]] + fi[i]);
else;
else
for (int j = si[i]; j <= 200000+si[i]; j ++)
if (f[j - si[i]] > inf)
f[j] = max(f[j], f[j - si[i]] + fi[i]);
int ans = 0;
for (int i = 100000; i <= 200000; i ++)
if (f[i] >= 0 && i - 100000 + f[i] > ans)
ans = i - 100000 + f[i];
printf("%d\n", ans);
return 0;
}
题目大意:N个有两个属性Si、Fi的物品,从中选出几个使得sigma(Si) + sigma(Fi)最大,并且两者都必须是非负数.
比较好的一道题,考查对01背包的理解和运用能力.
对于这种一个物品两个属性的问题,即使没有什么体积或者价值那么明显的情况,我们也应该考虑一下01背包是否可行.其实01背包不在于解决什么体积、价值问题,而在于这种动态规划的方法可以记录下来选择某些物品时,得到一个属性的值所对应的时刻另一个属性最优的状态.(这仅是我的拙见……)
那么显然我们就可以通过01背包来得到不同Si的值所对应能得到的Fi的最优值,然后通过枚举所有可能得到的Si值即可比较出最优解.
注意一点就是因为si[i]可能为负,所以范围要扩大一倍.
另外还需要注意对01背包第二层枚举顺序的理解:当si[i]>0时我们从大到小搜,当si[i]<0时从小到大搜.(理解不了的去看《背包九讲》吧~~)
(。。尼玛这题TLE+RE n次。。最后一看。。我们范围100000算成1000000了= =。。。捉鸡。。。
转载于:https://www.cnblogs.com/AbandonZHANG/archive/2013/02/12/4114217.html