POJ 2184 Cow Exhibition(01背包变形)

来源:互联网 发布:淘宝开店怎么做代理商 编辑:程序博客网 时间:2024/05/21 14:44

此题想了很久来着,因为是看背包专题做的题,后面提示是把其中一个量作为物品大小,另一个作为价值。我照这个思路把题目敲完了。因为有负值我想了2个思路,一个是把每一个都加上1000,然后就按照普通的01背包来做,但是这样会有一个问题,到时候扫描一遍找最大值的时候不知道选了几个,也就不知道减几个1000,是不是可以用加一个保存选个数的数组,这样也不行,因为如果 

dp[j] = dp[j - a[ i ]]+b[i],到底是要前者还是后者?也许是要看j - 要减的1000是不是正的?我觉得不靠谱,于是思路否决。。

第二个思路就很简单了,直接给背包加一个值mid=n*1000,这样背包就不会有负值了,但是递推的时候有个问题,如果用1维的,负数的时候跟它产生联系的是后面的不是前面的,就需要正推了,解决方案是分情况,其实还可以用滚动数组,直接推上一层的就不用讨论了,不过问题在于数组之间复制的时候耗费赶脚很长。。因为很大。

全部推完后,dp[j]代表容量为j的背包(可达到的)所获得的最大价值,也就是说聪明值为j最大可以有dp[ j ]的有趣值,这样只要从最大的扫描到mid,找出这2个值加起来(要减mid)的最大就是答案了。

做完这题后我有点想法,DP问题就是要找子问题,子问题如果推不出最终解或者得不到下一个子问题就是错误的,比如此题,如果想找聪明值和有趣值的和最大作为子问题肯定不行,因为题目说2者都要为正。要是一个1000,-50,另一个1000,-1,你就要把2个都选上了。因为2个的和都很大,但是其他的奶牛不一定能把有趣值变为正的,所以就是错误的子问题。


AC代码:

#include<cstdio>#include<ctype.h>#include<algorithm>#include<iostream>#include<cstring>#include<vector>#include<stack>#include<cmath>#include<queue>#include<set>#include<ctime>using namespace std;#define NMAX 100000#define ll long longint dp[200005];int s[105],f[105];int main(){//    freopen("input.txt","r",stdin);//    freopen("o1.txt","w",stdout);    int i,j,k,n;    while(~scanf("%d",&n))    {        int t1,t2;        for(k = i = 0; i < n; i++)        {            scanf("%d%d",&t1,&t2);            if(t1>=0 || t2>=0)            {                s[k] = t1;                f[k++] = t2;            }        }        int mid = k*1000,v = 2*mid;        for(i = 0; i <= v; i++) dp[i] = (i==mid)?0:-NMAX;        for(i = 0; i < k; i++)        {            if(s[i]>0)            {                for(j = v; j >= s[i]; j--)                    if(dp[j-s[i]] != -NMAX)                        dp[j] = max(dp[j],dp[j-s[i]]+f[i]);            }            else            {                for(j = 0; j <= v+s[i]; j++)                    if(dp[j-s[i]] != -NMAX)                        dp[j] = max(dp[j],dp[j-s[i]]+f[i]);            }        }        int ans = -1;        for(i = v; i >= mid; i--)            if(dp[i] >= 0 && dp[i]+i-mid > ans)                ans = dp[i]+i-mid;        printf("%d\n",ans);    }    return 0;}


0 0