POJ 2184 变形01背包

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. 

题目大意:选出一些牛,使smartness和funness值的和最大,而这些牛有些smartness或funness的值是负的,还要求最终的smartness之和以及funness之和不能为负。

分析:这里不就是看哪些牛选,还是不选的问题吗,那么这就是转化为01背包,在这里可以将smartness当做01背包中的体积,funness当做01背包里面的价值,当然你也可以将两者倒过来也是可以的,在代码中我默认市容smartness当做体积;

然后这道题还有一个需要进一步处理的方式就是如何处理,当价值为负数的情况,以前也处理过类似的,方法就是将下标左移扩大,因为所给的数据为[-1000,1000],因此我可以将其变为[0,2000],那么整个背包的体积的使用范围为[0*100,2000*100],那么此时的原点,也就是对称点变为100000,此时dp[100000]=0;其他情况初始化为负无穷,这样在[0,100000]区间里的是原区间[-1000,0],相应的[100000,200000]就是[0,1000];

还有一个地方需要注意的就是当体积为负数的时候与体积为正数的时候的处理情况是不同的;我们在运用一维数组优化01背包的时候说过,推dp的时候是从后往前推,当体积为正数的时候是没有问题,就按照原来的方法套模板,但是当为负数的时候就需要按照正序走一遍dp了(原因);dp[i]是数据中左边一列s的和为s时的最大f值,而s+f=dp[i]+i-10000;

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ms(arr) memset(arr,0,sizeof(arr))
const int N=2000100;
const int INF=0x3f3f3f3f;
int dp[N];
int a[200],b[200];
int main()
{
//    freopen("in.txt","r",stdin);
   int n;
   scanf("%d",&n);
   rep(i,0,200000)
   dp[i]=-INF;
   dp[100000]=0;
   rep(i,1,n){
   scanf("%d%d",&a[i],&b[i]);
   if(a[i]<=0&&b[i]<=0) i--,n--;
   }
   rep(i,1,n)
   {
       if(a[i]>0)
       {
           for(int j=200000;j>=a[i];j--)
           if(dp[j-a[i]]>-INF)//这个和下面的两个if不能去掉,否则会Running Error
           dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
       }else{
           for(int j=a[i];j<=200000+a[i];j++)
           if(dp[j-a[i]]>-INF)
           dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
       }
   }
   int ans=-INF;
   rep(i,100000,200000)
   if(dp[i]>=0)
    ans=max(ans,dp[i]+i-100000);
   printf("%d\n",ans);
    return 0;
}

至于为什么上面两个if去掉之后会Running Error,不清楚为什么,望知道的大神能够指出

猜你喜欢

转载自blog.csdn.net/c___c18/article/details/82982672
今日推荐