Cow Exhibition (01揹包的負數處理)
奶牛想證明他們是聰明而風趣的。為此,貝西籌備了一個奶牛博覽會,她已經對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; }