日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

完全背包dp优化

發布時間:2025/4/5 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 完全背包dp优化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

01背包:每個物品只能選擇一次
狀態轉移方程
f[i][j]=max(f[i][j],f[i?1][j?v]+w)f[i][j]=max(f[i][j],f[i-1][j-v]+w)f[i][j]=max(f[i][j],f[i?1][j?v]+w)

完全背包:每個物品可以選擇無數次

狀態轉移方程
f[i][j]=max(f[i][j],f[i][j?v]+w)f[i][j]=max(f[i][j],f[i][j-v]+w)f[i][j]=max(f[i][j],f[i][j?v]+w)
其中v表示第i個物品的體積,w表示第i個物品的價值

狀態表示
集合:從前i個物品中選,體積不超過j
屬性:最大值max
?f[i][j]\Rightarrow f[i][j]?f[i][j]表示只從前i個物品中選,并且體積不超過j的方案的最大價值。
狀態計算
對于f[i][j]f[i][j]f[i][j],劃分集合,可以劃分為很多個
對于第i個物品,我們不選,對應的最大價值:f[i?1][j]f[i-1][j]f[i?1][j]
對于第i個物品,我們只選1個,對應的最大價值:f[i?1][j?v]+wf[i-1][j-v]+wf[i?1][j?v]+w
對于第i個物品,我們只選2個,對應的最大價值:f[i?1][j?2v]+2wf[i-1][j-2v]+2wf[i?1][j?2v]+2w
不失一般性,選擇k個,對應的最大價值:f[i?1][j?kv]+kwf[i-1][j-kv]+kwf[i?1][j?kv]+kw
只要不超過背包容量m的限制,可以一直選擇下去,假設最多放k件物品。
所以,狀態計算的方程為上述計算結果的最大值:
f[i][j]=max(f[i?1][j],f[i?1][j?v]+w,f[i?1][j?2v]+2w,...,f[i?1][j?kv]+kw,)(1)f[i][j]=max(f[i-1][j],f[i-1][j-v]+w,f[i-1][j-2v]+2w,...,f[i-1][j-kv]+kw,)(1)f[i][j]=max(f[i?1][j],f[i?1][j?v]+w,f[i?1][j?2v]+2w,...,f[i?1][j?kv]+kw,)1

使用變量代換:令j=j-v,此時f[i][j?v]f[i][j-v]f[i][j?v]表示只在前i個物品中選,背包容量不超過j-v的方案的價值最大值。

f[i][j?v]=max(f[i?1][j?v],f[i?1][j?2v]+w,f[i?1][j?3v]+2w,...,f[i?1][j?kv]+(k?1)w,)f[i][j-v]=max(f[i-1][j-v],f[i-1][j-2v]+w,f[i-1][j-3v]+2w,...,f[i-1][j-kv]+(k-1)w,)f[i][j?v]=max(f[i?1][j?v],f[i?1][j?2v]+w,f[i?1][j?3v]+2w,...,f[i?1][j?kv]+(k?1)w,)

這里并沒有增加一項f[i?1][j?(k+1)v]+kwf[i-1][j-(k+1)v]+kwf[i?1][j?(k+1)v]+kw,這是因為背包容量從j變成了j-v,如果背包容量為j時最多可以放k件物品,那么背包容量為j-v時,背包最多可以放k-1件物品。

我們發現
即(1)式的后半部分可以使用f[i][j-v]+w來表示
所以,最后的狀態轉移方程
f[i][j]=max(f[i][j],f[i][j?v]+w)f[i][j]=max(f[i][j],f[i][j-v]+w)f[i][j]=max(f[i][j],f[i][j?v]+w)
ac代碼(樸素解法)

#include<iostream> #include<cstring> using namespace std;const int maxn=1010;int n,m,dp[maxn][maxn],a[maxn],v[maxn],w[maxn]; int main(){cin>>n>>m;//讀入物品數目,背包容量//base case memset(dp,0,sizeof(dp));//數組全部置零for(int i=1;i<=n;i++){//從1開始存cin>>v[i]>>w[i];//讀入每件物品的體積和價值}for(int i=1;i<=n;i++)//狀態轉移for(int j=1;j<=m;j++){dp[i][j]=dp[i-1][j];if(j>=v[i])//背包放得下dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i]);}cout<<dp[n][m]<<endl; }

ac代碼(空間優化解法)

主要代碼
dp[j-v[i]]小于dp[j],此時從小到大遍歷背包容量時,dp[j-v[[i]]已經更新到本層,而不是上一層。滿足//相當于dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i])
根據閆氏dp分析法, 代碼更改之后需要邏輯沒變,發現等價后沒變。

for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){dp[j]=dp[j];//相當于dp[i][j]=dp[i-1][j]if(j>=v[i])//背包容量為j時的最大價值 dp[j]=max(dp[j],dp[j-v[i]]+w[i]);//相當于dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i])}cout<<dp[m]<<endl;//輸出背包容量為m時的結果

這樣我們就省掉了空間。

#include<iostream> #include<cstring> using namespace std;const int maxn=1010;int n,m,dp[maxn],a[maxn],v[maxn],w[maxn]; int main(){cin>>n>>m;memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++){cin>>v[i]>>w[i];}for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){//遍歷背包容量if(j>=v[i])dp[j]=max(dp[j],dp[j-v[i]]+w[i]);//背包容量為j時的最大價值 }cout<<dp[m]<<endl;//輸出背包容量為m時的結果 }

更精簡的寫法
把遍歷背包容量直接提到循環里面for(int j=v[i];j<=m;j++)

#include<iostream> #include<cstring> using namespace std;const int maxn=1010;int n,m,dp[maxn],a[maxn],v[maxn],w[maxn]; int main(){cin>>n>>m;memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++){cin>>v[i]>>w[i];}for(int i=1;i<=n;i++)//遍歷物品 for(int j=v[i];j<=m;j++){//遍歷背包容量 dp[j]=max(dp[j],dp[j-v[i]]+w[i]);//背包容量為j時的最大價值 }cout<<dp[m]<<endl;//輸出背包容量為m時的結果 }

以后寫完全背包就寫優化后的解法

總結

以上是生活随笔為你收集整理的完全背包dp优化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。