背包问题(poj2184)

来源:互联网 发布:telnet无法连接端口 编辑:程序博客网 时间:2024/06/05 17:17

Cow Exhibition

 Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

 

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 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头牛中选择若干头牛去参加比赛,假设这若干头牛的聪明度之和为sumS,风趣度之和为sumF现要求在所有选择中,在使得sumS>=0&&sumF>=0的基础上,使得sumS+sumF最大并输出其值。
思路:其实这道题和普通0-1背包差不多,只是要转换下思想,就是在求fun[j]中可以达到的最大smart。
我们设聪明度属性为费用,风趣度属性为价值,问题转换为求费用大等于0时的费用、价值总和。因为当聪明度和为x的时候,可能有若干个风趣度和与之对应,但我们只选择一个最大值,所以动态维护这个x对应的最大风趣度和就行了,和上面说的背包模型等价。 
由于本题的费用可能为负数,虽然最后的结果中不能有费用和为负数的情况,但中间的状态可能为负数,而负数的转移过程和正数的方向相反,要分开写。把负数映射到大于20万的地方,其实10万就可以了,但是在允许的情况开大点保险。 一共100组数,从-1000到1000,那么体积的范围就是-100*1000到100*1000。平移之后我们要处理的数据范围就在0到200000,新的原点变成100000。  状态转移方程:dp[j] = max(dp[j],dp[j-cost[i]+val[i]) (1<=i<=n,sumpos<=j<=sumneg),在一般的01背包压缩空间的时候,体积的遍历是从大到小,因为dp[v]=max(dp[v],dp[v-c[i]]+w[i]),当前的dp[v]只取决于比自己小的dp[v-c[i]],所以从大到小遍历时每次dp[v-c[i]]和dp[v]都是上一次的状态。如果体积为负v-c[i]>v,从大到小遍历dp[v-c[i]]是当前物品的状态,不是上一个,这样就会出错,解决的办法是从小到大遍历。注意由于smart可以是负的,要把smart整体加100*1000。当s[i]为负数时,从递增遍历,因为01背包是每个物品只用一次的,而当si为负的时候,恰恰需要我们从小往大搜,保证每个si只用一次,这也是01背包和完全背包的重要区别 

代码

#include<iostream>#include<cstdio>using namespace std;int dp[200010],minn,maxn;struct D{    int s,f;}n[104];void init(int N){    for(int i=0;i<N;i++)    cin>>n[i].s>>n[i].f;}int maxi(int x,int y){    if(x>y)       return x;    else return y;}int main(){    int N,i,j;    while(~scanf("%d",&N))    {        init(N);        for(i=0;i<=200010;i++)            dp[i]=-1000000;        dp[100000]=0;//当所有的数全为负数时,用来输出0        for(i=0;i<N;i++)        {            if(n[i].s>0)//空间度大于0,从大到小                for(j=200010;j>=n[i].s;j--)                {                    dp[j]=maxi(dp[j-n[i].s]+n[i].f,dp[j]);                }             else for(j=0;j<=200010+n[i].s;j++)//空间度小于0,从小到大            {                dp[j]=maxi(dp[j-n[i].s]+n[i].f,dp[j]);            }         }         int ans=0;         for(i=100000;i<=200010;i++)            if(dp[i]>=0)                ans=maxi(ans,i-100000+dp[i]);         printf("%d\n",ans);         }         return 0;         }


原创粉丝点击