[POJ2184]Cow Exhibition(01背包)

来源:互联网 发布:ubuntu使用windows软件 编辑:程序博客网 时间:2024/05/21 10:14

题目:

我是超链接

题意:

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);    }}