题目大意:已知c[i]...c[n]及f[i]...f[n],现要选出一些i,使得当sum{c[i]}和sum{f[i]}均非负时,sum(c[i]+f[i])的最大值。
以sum(c[i])(c[i]>=0)作为背包容量totV,i当作物体,c[i]当作物体体积,f[i]当作物体重量,01背包后,求max{j+DP[j]} (非负)即可。
注意:
- 这里物体体积存在负数,所以循环j时起始条件不能为j=0!而应当在for下面加if,判断子问题在minJ~maxJ范围之内。
- 初值不是DP[最左端点]=0,而是DP[0点所在位置]=0。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAX_V = 200010, MAX_OBJ = 110; #define M(x) x+offset//move int DP(int minJ, int maxJ, int totObj, int *_v, int *_w) { static int DP[MAX_V]; int offset = max(-minJ, 0); memset(DP, 0xcf, sizeof(DP)); DP[M(0)] = 0; for (int i = 1; i <= totObj; i++) { if (_v[i] <= 0) { for (int j = minJ; j <= maxJ; j++) if (j >= minJ + _v[i] && j <= maxJ + _v[i]) DP[M(j)] = max(DP[M(j)], DP[M(j - _v[i])] + _w[i]); } else { for (int j = maxJ; j >= minJ; j--) if (j >= minJ + _v[i] && j <= maxJ + _v[i]) DP[M(j)] = max(DP[M(j)], DP[M(j - _v[i])] + _w[i]); } } int ans = 0; for (int j = 0; j <= maxJ; j++) if(DP[M(j)] >=0) ans = max(ans, j+DP[M(j)]); return ans; } int main() { #ifdef _DEBUG freopen("c:\noi\source\input.txt", "r", stdin); #endif static int _s[MAX_OBJ], _f[MAX_OBJ]; int n, minS = 0, maxS = 0, cnt = 0, s, f, tempAns = 0; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d%d", &s, &f); if (s >= 0 && f >= 0) { tempAns += s + f; continue; } else if (s <= 0 && f <= 0) continue; else { cnt++; _s[cnt] = s; _f[cnt] = f; _s[cnt] > 0 ? maxS += _s[cnt] : minS += _s[cnt]; } } printf("%d ", tempAns + DP(minS, maxS, cnt, _s, _f)); return 0; }