当前位置: 代码迷 >> 综合 >> POJ 2184 Cow Exhibition 0-1背包变种之处理负值 dp循环方向理解
  详细解决方案

POJ 2184 Cow Exhibition 0-1背包变种之处理负值 dp循环方向理解

热度:75   发布时间:2023-12-20 23:34:49.0

题目链接

Description
“Fat and docile, big and dumb, they look so stupid, they aren’t much
fun…”
-Cows with Guns by Dana Lyons
The cows want to prove to the public that they are both smart and fun. In order to do this, Bessie has organized an exhibition that will be put on by the cows. She has given each of the N (1 <= N <= 100) cows a thorough interview and determined two values for each cow: the smartness Si (-1000 <= Si <= 1000) of the cow and the funness Fi (-1000 <= Fi <= 1000) of the cow.
Bessie must choose which cows she wants to bring to her exhibition. She believes that the total smartness TS of the group is the sum of the Si’s and, likewise, the total funness TF of the group is the sum of the Fi’s. Bessie wants to maximize the sum of TS and TF, but she also wants both of these values to be non-negative (since she must also show that the cows are well-rounded; a negative TS or TF would ruin this). Help Bessie maximize the sum of TS and TF without letting either of these values become negative.
Input
Line 1: A single integer N, the number of cows
Lines 2…N+1: Two space-separated integers Si and Fi, respectively the smartness and funness for each cow.
Output
Line 1: One integer: the optimal sum of TS and TF such that both TS and TF are non-negative. If no subset of the cows has non-negative TS and non- negative TF, print 0.
Sample Input
5
-5 7
8 -6
6 -3
2 1
-8 -5
Sample Output
8
Hint
OUTPUT DETAILS:
Bessie chooses cows 1, 3, and 4, giving values of TS = -5+6+2 = 3 and TF
= 7-3+1 = 5, so 3+5 = 8. Note that adding cow 2 would improve the value
of TS+TF to 10, but the new value of TF would be negative, so it is not
allowed.

大致题意:
共有N头牛,接下来N行是每头牛的智商和情商,从这些牛中任选若干头,使得牛的智商和(TS)+情商和(TF)最大,同时智商和(TS),情商和(TF)都不小于0。

解题思路:
以智商为容量,求前i头牛在智商为j的情况下的最大情商,将问题转化为0-1背包之恰好装满一定的容积

dp[j]:=前i头牛在智商为j的情况下的最大情商
将i从1到n遍历,同时更新dp[j]
状态转移方程:dp[j]=max(dp[j], dp[j-w[i]]+v[i])
-1000 <= Si <= 1000     1=<n<=100

为了避免负数作为下标,智商和(TS)都加上100000,整体的范围就变为[0,200000]

初始化时dp[100000]=0,其余的dp[j]=-INF 这里我们用-INF表示不存在的情况(因为需要恰好装满体积 j ,所以我们可以先判断前提条件存不存在)

w[i]>0时,dp[j]的计算顺序为从大往小计算,因为在计算前i头牛的最优情商和时,dp[j-w[i]]是前i-1头牛的最优情商和,而这个值在dp[j]的左侧,所以我们从右往左计算,这样就可以利用前i-1的解,不会覆盖。
同理当w[i]<=0时,dp[j]的计算顺序为从小往大计算,因为dp[j-w[i]]这个时候在dp[ j ]的右侧了。
(想一想数组重复利用的过程便不难理解了)

AC代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;int dp[200005];
int w[101]; int v[101];
#define M 100000
#define INF 0x3fffffff
int main() {
    int n;cin >> n;for (int i = 1; i <= n; i++) {
    cin >> w[i] >> v[i];}for (int i = 0; i <= 200000; i++) {
     dp[i] = -INF; }dp[100000] = 0;for (int i = 1; i <= n; i++) {
    if (w[i] > 0) {
    for (int j = 200000; j >= w[i]; j--) {
    if (dp[j - w[i]] != -INF) {
    //前置条件成立dp[j] = max(dp[j], dp[j - w[i]] + v[i]);}}}else {
    for (int j = 0; j <= 200000+w[i]; j++) {
    if (dp[j - w[i]] != -INF) {
    //前置条件成立dp[j] = max(dp[j], dp[j - w[i]] + v[i]);}}}}int ans = 0;for (int i = 100000; i <= 200000; i++) {
    if (dp[i] < 0)continue;ans = max(ans, dp[i] + i - 100000);}cout << ans << endl;//system("pause");
}

解题过程中参考的大神博客:
POJ 2184 Cow Exhibition (处理负值的01背包)