dp背包之01背包poj2184
http://poj.org/problem?id=2184
题意:给定两个属性,求这两个属性的和的最大值.........
思路:将第一个属性往后平移1000个单位,然后推导其动态转移方程,若是dp[i],代表当加入第一个属性加到i时,符合题意的第二个属性的最大值......题意是两个属性的和的最大值,那么动态转移方程必然不是dp[j]=max(dp[j],dp[j-s[i][0]]+s[i][1]),因为这个动态转移方程固然可以求出第二个属性的最大值,但别忘了题意要求第一个属性与第二个属性的和的最大值,那么,第一个属性平移了1000个单位,在考虑动态转移时,是必须要将这个考虑进去的。可以开一个a数组记录路径,然后根据题意,
动态转移方程应该为dp[j]=max(dp[j]-a[j]*1000,dp[j-s[i][0]]+s[i][1]-(a[j-s[i][0]]+1)*1000),一开始a数组全部赋值为0,所以需要a[j-s[i][0]]+1.....因为它新加入了一个值。考虑这个方程,dp数组的初始全部赋值为负无穷大,dp[0]=0。
注意一点,在历遍查找最大值的时候,dp[i]>0,i-a[i]*1000>0
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; #define maxx 1000005 int s[maxx][2],dp[maxx],a[maxx]; int main() { int n; while(scanf("%d",&n)>0) { int sum=0; for(int i=1;i<=n;i++) { scanf("%d %d",&s[i][0],&s[i][1]); if(s[i][0]<0&&s[i][1]<0) { i--; n--; continue; } s[i][0]+=1000; sum+=s[i][0]; } memset(a,0,sizeof(a)); for(int i=0;i<=sum;i++) dp[i]=-maxx; dp[0]=0; for(int i=1;i<=n;i++) { for(int j=sum;j>=s[i][0];j--) if(dp[j]-a[j]*1000<dp[j-s[i][0]]+s[i][1]-(a[j-s[i][0]]+1)*1000) { dp[j]=dp[j-s[i][0]]+s[i][1]; a[j]=a[j-s[i][0]]+1; } } int maxn=0; for(int i=1;i<=sum;i++) if(maxn<dp[i]-a[i]*1000+i&&dp[i]>=0&&i-a[i]*1000>=0) maxn=dp[i]-a[i]*1000+i; printf("%d\n",maxn); } return 0; }
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。