奶牛想证明他们是聪明而风趣的。为此,贝西筹备了一个奶牛博览会,她已经对N头奶 牛进行了面试,确定了每头奶牛的智商和情商。 贝西有权选择让哪些奶牛参加展览。由于负的智商或情商会造成负面效果,所以贝西不 希望出展奶牛的智商之和小于零,或情商之和小于零。满足这两个条件下,她希望出展奶牛 的智商与情商之和越大越好,请帮助贝西求出这个最大值Input第一行:一个整数N,表示奶牛的数量, 1 ≤ N ≤ 100 第二行到第N + 1行:第i + 1行有两个用空格分开的整数: Si和Fi,分别表示第i头奶牛的智商和情商, -1000 ≤ Si ≤ 1000, -1000 ≤ Fi ≤ 1000Output第一行:单个整数,表示情商与智商和的最大值。贝西可以不让任何奶牛参加展览,如 果这样应该输出0Sample Input
5 -5 7 8 -6 6 -3 2 1 -8 -5
Sample Output
8
Hint选择 1, 3, 4 号奶牛,此时智商和为-5 + 6 + 2 = 3,情商和为7 - 3 + 1 = 5。加 入 2 号奶牛可使总和提升到10,不过由于情商和变成负的了,所以是不允许的
我们可以写出dp[2]=3; dp[8]=4;就是这个道理,最后再把8+4=12就行了。
我们令dp[100000]=0,因为其他的值都有可能是负数,所以我们把其他的都赋值为负无穷。
以100000作为原点,这样dp括号里的容量就不会为负数了
如同01背包一样,如果TS[i]是正数,则有如下循环: for(i=0;i<n;i++) { if(TS[i]>0) for(j=200000;j>=TS[i];j--) dp[j]=max(dp[j],dp[j-TS[i]]+TF[i]); } 如果是负数,则是: for(i=0;i<n;i++) { if(TS[i]<=0) for(j=0;j-TS[i]<=200000;j++) dp[j]=max(dp[j],dp[j-TS[i]]+TF[i]); }
为什么TS[i]为负数是要用正序循环
在标准的01背包里,我们看见j>j-TS[i],也就是说我们要想求dp[j],我们必须用到上一层的dp[j]和dp[j-TS[i]],也就是要用到上一层的他自己dp[j]与自变量j-TS[i]小于自己的[j]的dp[j-TS[i]],如果正序的话,dp[j-TS[i]]就会被破坏掉。
同样的,如果TS[i]是负数,j-TS[i]>j,如果我们要求dp[j],我们要用到上一层的dp[j]与上一层的自变量j-TS[i]大于j的dp[j-TS[i]],如果按照逆序循环,dp[j-TS[i]]会被破坏掉。
for(j-TS[i]=200000;j>=0;j--) dp[j]=max(dp[j],dp[j+TS[i]]+TF[i]);
这也是不可以的。
因为当TS[i]是负数的时候,dp[j]括号中的这个容量应该由大容量推来。比如说你要算dp[100003],那你就应该由dp[100004]等等推来。也就是说你要保证max中的后边的dp括号中的自变量要大于前边的dp。
下面给出文章开头例子的计算过程:
第一次,s[0]=-5<0; 可得 { dp[99995]=7; dp[100000]=0; } 第二次,s[1]=8>0 { dp[99995]=7; dp[100000]=0; dp[100003]=1 }; 第三次,s[2]<0; { dp[99993]=10; dp[99995]=7; dp[100003]=1; dp[100001]=4; }
最后说明求总和的最大值:
因为我们要保证TS[i]和TF[i]的和分别都大于0,TS[i]的和用dp[]括号里的值是否大于100000来保证,只要大于100000,说明TS[i]的总和没有是负数。这个是显而易见的,比如说dp[99995]=7,代表在TS[i]的和是-5的情况下,所获的最大价值是7.
再就是保证TF[i]的和大于0,这个通过dp[]的值来保证,值大于0说明TF[i]总和大于0.
所以我们利用如下循环,就可以求出总和的最大值:
for(i=100000;i<=200000;i++) { if(dp[i]>=0) l=max(l,i+dp[i]-100000); }
下面是我自己的理解
就是说数组的下标不可负数,那就让它有一个偏移量(就是说再设置一个起点100*1000为0点)
正数的时候反着跟更新,负数的时候正着更新
代码:
#include<iostream> #include<cstring> #include<algorithm> using namespace std; const int INF=0x3f3f3f3f; const int maxn=5e5+100; int a[maxn]; int b[maxn]; int dp[maxn];//dp[i][j]指的是 int n; int main(){ cin>>n; memset(dp,-INF,sizeof(dp)); for(int i=1;i<=n;i++){ cin>>a[i]>>b[i]; } dp[100000]=0; for(int i=1;i<=n;i++){ if(a[i]>0){ for(int j=200000;j>=a[i];j--){ dp[j]=max(dp[j],dp[j-a[i]]+b[i]); } } else{ for(int j=0;j<=200000+a[i];j++){ dp[j]=max(dp[j],dp[j-a[i]]+b[i]); } } } int ans=0; for(int i=100000; i<=200000;i++){ if(dp[i]>0){ ans=max(ans,dp[i]+i-100000); } } cout<<ans<<endl; return 0; }