[POJ2184]Cow Exhibition(01背包)

题目:

我是超链接

题意:

n个元素,每个元素都有两种属性s[i]和f[i],满足abs(s[i]),abs(f[i])<=m,现在从中选取若干个元素,使得所有s[i]之和>=0,所有f[i]之和>=0,且最大化s[i]+f[i]的值;n<=100,m<=1000,你可以一个元素也不选

题解:

真是一道01背包的好题?
最大的累计值为100000,但可能有负,我们就要设计0~200000的
注意如下:
1、这种有两个量而且范围很大的可以一维当成数组下标,另一维当成累加的量,因为要求两个数分别的和都大于0,第二个数直接从大于0的范围内找
2、我们都知道s[i]为正数时01背包要从大到小循环,可以保证只选一次;如果s[i]为负数,01背包就要从小到大循环了,这样才能保证只选一次!(s[i]是数组下标!)

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int dp[200005],s[105],f[105];
int main()
{
    int n,i,j;
    while (scanf("%d",&n)!=EOF)
    {
        memset(dp,0x8f,sizeof(dp));
        int Minn=dp[0];
        dp[100000]=0;
        for (i=1;i<=n;i++) scanf("%d%d",&s[i],&f[i]);
        for (i=1;i<=n;i++)
        {
            if (s[i]<0 && f[i]<0) continue;
            if (s[i]<0) 
            {
                for (j=s[i];j<=s[i]+200000;j++)
                  if (dp[j-s[i]]>Minn) dp[j]=max(dp[j-s[i]]+f[i],dp[j]);
            }
            else 
            {
                for (j=200000;j>=s[i];j--)
                  if (dp[j-s[i]]>Minn) dp[j]=max(dp[j-s[i]]+f[i],dp[j]);
            }
        }
        int ans=0;
        for (i=100000;i<=200000;i++)
          if (dp[i]>=0) ans=max(ans,dp[i]+i-100000);
        printf("%d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值