// [7/21/2014 Sjm]
/*
题意:maximize the sum of TS and TF, but both of these values to be non-negative.
解决思路:
以 TS 作为体积,TF作为价值,在保证体积、价值非负的情况下,求解 sum,取其所有情况的最大值。
难点:
1)体积出现负数,将区间改变 [-100000, 100000] ---> [0, 200000]。
(注意此时始点 dp[100000], [0, 100000)表示 TS 为负,(100000, 200000]表示 TS 为正)
2)状态转移时,对于 smartness 出现负数的处理
(二维更好理解一些,但是若写成一维,则注意内层循环的循环顺序(思想同“背包九讲”里的“优化空间”的方法))
(在我看来:关键是对状态转移方程的理解程度,知道所求值是依赖谁求出来的,在一维数组中各个值的位置又在哪里)
3)千万注意初始化,因为要保证“必须把背包装满”。。。
1 #include <iostream>
2 #include <cstdlib>
3 #include <cstdio>
4 #include <algorithm>
5 #include <cstring>
6 using namespace std;
7 const int MAX = 200005;
8 const int INF = 0x3f3f3f3f;
9 int arr[105][2], dp[MAX];
10 int sum, N;
11
12 int Solve() {
13 memset(dp, -INF, sizeof(dp));
14 dp[100000] = 0;
15 for (int i = 1; i <= N; ++i) {
16 if (arr[i][0] > 0) {
17 for (int j = sum; j >= arr[i][0]; --j) { // 注意循环顺序,从大到小
18 if (dp[j - arr[i][0]] > -INF) {
19 dp[j] = max(dp[j], dp[j - arr[i][0]] + arr[i][1]);
20 }
21 }
22 }
23 else {
24 for (int j = 0; j <= sum + arr[i][0]; ++j) { // 注意循环次序,从小到大
25 if (dp[j - arr[i][0]] > -INF) {
26 dp[j] = max(dp[j], dp[j - arr[i][0]] + arr[i][1]);
27 }
28 }
29 }
30 }
31 int ans = 0;
32 // 由 TS 非负值的计算结果
33 for (int i = sum; i >= 100000; --i) {
34 if (dp[i] >= 0) { // 保证 TF 非负
35 ans = max(ans, dp[i] + i - 100000);
36 }
37 }
38 return ans;
39 }
40
41 int main()
42 {
43 //freopen("input.txt", "r", stdin);
44 scanf("%d", &N);
45 int sum1 = 0, sum2 = 0;
46 for (int i = 1; i <= N; ++i) {
47 scanf("%d %d", &arr[i][0], &arr[i][1]);
48 if (arr[i][0] > 0) {
49 sum += arr[i][0];
50 }
51 }
52 sum = sum + 100000; // TS 上界
53 printf("%d
", Solve());
54 return 0;
55 }