背包的第k優解[動態規劃]
阿新 • • 發佈:2017-11-04
open tail height val 技術 colspan esp output 理解
慢慢啃
f[j][u]表示空間為j時的第u優解;
性質:加了一個u循環操作的01背包,i表示加入第i個物品則循環順序從外到裏為i->j->u(就是把原本f[j]=max(f[j-w[i]]+v[i],f[j])的位置變成u的循環操作而已);
初始化:
f[j][u]=負無窮(u循環操作前要判定f[j-w[i]][1]>=0),f[0][1]=0;
u的循環操作:
1.已知f[j]=max(f[j-w[i]]+v[i],f[j]),即f[j]有兩種取值方案;
用兩個數組st1[u]和st2[u]分別儲存f[j-w[i]][u]+v[i]和f[j][u];
2.因為f[j][u]一定優於f[j][u+1],所以st1[u]一定優於st1[u+1],st2[u]同理,所以只需要比較st1和st2中的元素就可以得到當前可以取到的最優值;
所以f[i][u]等於st1[tail1]和st2[tail2]中較大的;
3.因為不能有一樣的方案,所以st1[tail1],st2[tail2]中較大的數被f[i][u]取值後,對應的tail++(tail在u循環開始前定義為0或者1);
隨著j的增大,方案數是樹狀增多的,但是前u個最優方案一定是在這棵樹的某一個分支上,這個分支的父節點一定是某一個階段的最優方案,就像分封制一樣,離最後的最優方案血緣關系越遠優秀程度越差,嗯我是這麽理解的.....
因為動態規劃每一個階段的方案只和前一個階段有關,所以可以在輸入數據後直接j循環,不需要v[i]w[i]之類存儲每一個狀態的數組...
|
||
|
性質:加了一個u循環操作的01背包,i表示加入第i個物品則循環順序從外到裏為i->j->u(就是把原本f[j]=max(f[j-w[i]]+v[i],f[j])的位置變成u的循環操作而已);
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int k,v,n; 8 long long f[5010][51]={}; 9 long long st1[5010]={}; 10 long long st2[5010]={}; 11 int main(){ 12 cin>>k>>v>>n; 13 for(int i=0;i<v;i++){ 14 for(int j=0;j<=k;j++){ 15 f[i][j]=-99999999; 16 } 17 } 18 f[0][1]=0; 19 for(int i=1;i<=n;i++){ 20 int a,b; 21 cin>>a>>b; 22 for(int j=v;j>=a;j--){ 23 if(f[j-a][1]>=0){ 24 int p1=1,p2=1; 25 for(int u=1;u<=k;u++){ 26 st1[u]=f[j-a][u]+b; 27 st2[u]=f[j][u]; 28 if(st2[p2]>=st1[p1]) f[j][u]=st2[p2++]; 29 else f[j][u]=st1[p1++]; 30 } 31 } 32 } 33 } 34 long long ans=0; 35 for(int i=1;i<=k;i++){ 36 ans+=f[v][i]; 37 } 38 cout<<ans<<endl; 39 return 0; 40 }View Code
背包的第k優解[動態規劃]