题意:每头牛有smart值和funness值,求出在smart值的和>0&&funness值>0的情况下,smart值和funness值的总和最大。
分析:转化成01背包问题,每头牛选不选就相当于每件物品选与不选,把牛的smart值看做体积,funness看做价值,则对应dp[j]表示前i件物品放入到体积为j的背包里所达到的最大价值
然后对于一个0-1背包问题,我们的递推公式是
for(int i=W;i>=w[i];i--)
dp[i]=dp[i-w[i]]+v[i]
在这里有一个比较棘手的点就在于如果我们将smart值作为体积,那么体积会有负数,因此我们将数组开到 M A X ∗ 2 MAX*2 MAX∗2,大于MAX的用于表示正数,小于MAX用于表示负数,比如 d p [ M A X + 1 ] dp[MAX+1] dp[MAX+1]就表示smart为1时,最大的funness的值, d p [ M A X − 1 ] dp[MAX-1] dp[MAX−1]就代表smart和为 − 1 -1 −1时,最大的funness的值。然后对每一个 s m a r t ≥ 0 smart\geq 0 smart≥0的元素,我们从右向左进行遍历
for (int j = sum; j >= smart[i]; j--)//正:从右向左
if (dp[j - smart[i]] != -inf) {
dp[j] = max(dp[j], dp[j - smart[i]] + fun[i]);
}
需要注意的是,这里的sum是我们为了简化程序所计算的所有正的smart的和,也是最大的smart,因此 d p dp dp的索引值不会超过他,而索引值又必须大于0,因此 j ≤ s m a r t [ i ] j\leq smart[i] j≤smart[i],相反对于每一个 s m a r t < 0 smart<0 smart<0的元素,我们有
for (int j = 0; j <= sum; j++)//负:从左到右
if (dp[j - smart[i]] != -inf) {
dp[j] = max(dp[j], dp[j - smart[i]] + fun[i]);
}
最后计算结束后,我们统计所有KaTeX parse error: Expected 'EOF', got '&' at position 11: i\geq MAX &̲& dp[i]>0的满足条件的 s m a r t [ i ] + f u n n e s s [ i ] smart[i]+funness[i] smart[i]+funness[i]的最大值即可。
#define inf 0x3f3f3f3f
#define vec vector<int>
#define P pair<int,int>
#define ll long long
#define MAX 100005
int N, dp[MAX*2], F[105], T[105];
int main() {
while (scanf("%d", &N) != EOF) {
fill(dp, dp + 2*MAX, -inf);
dp[MAX] = 0;
int sum = MAX;
for (int i = 1; i <= N; i++) {
scanf("%d %d", &F[i], &T[i]);
if (F[i] > 0)sum += F[i];
}
for (int i = 1; i <= N; i++) {
if (F[i] >= 0) {
for (int j = sum; j >= F[i]; j--)//正:从右向左
if (dp[j - F[i]] != -inf) {
dp[j] = max(dp[j], dp[j - F[i]] + T[i]);
}
}
else
for (int j = 0; j <= sum; j++)//负:从左到右
if (dp[j - F[i]] != -inf) {
dp[j] = max(dp[j], dp[j - F[i]] + T[i]);
}
}
int ma = 0;
for (int i = MAX; i <= sum; i++)
if (dp[i] > 0 && dp[i] + i - MAX > ma)
ma = dp[i] + i - MAX;
cout << ma << endl;
}
}