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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

01背包问题dp优化

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

背包容量m給定,選擇n件物品,求放入背包的最大價值。
其中,物品只能選擇一次,要么放,要么不放。

樸素解法

經典的DP問題

狀態:f[i][j]f[i][j]f[i][j]表示選擇前iii個物品,背包容量為jjj時的最大價值
狀態轉移:
分為兩種情況

  • 所有不選第iii件物品的方案,那么此時最大價值和選擇前i?1i-1i?1件物品相等,即f[i][j]=f[i?1][j]f[i][j]=f[i-1][j]f[i][j]=f[i?1][j]
  • 所有選擇第iii件物品的方案,對于第iii件物品,其體積v[i]v[i]v[i] 需要預留出來, 價值是w[i]w[i]w[i]. 則此時的價值等于 第iii件物品的價值,加上前i?1i-1i?1件物品放入容量為j?v[i]j-v[i]j?v[i]的背包的價值,即f[i][j]=w[i]+f[i?1][j?v[i]]f[i][j]=w[i]+f[i-1][j-v[i]]f[i][j]=w[i]+f[i?1][j?v[i]]
    綜上兩種情況,狀態轉移方程是
    f[i][j]=max(f[i?1][j],w[i]+f[i?1][j?v[i]])f[i][j]=max(f[i-1][j],w[i]+f[i-1][j-v[i]])f[i][j]=max(f[i?1][j],w[i]+f[i?1][j?v[i]])
  • ac代碼

    #include<iostream> #include<cstring> using namespace std;const int maxn=1e3+10; int n,m; int v[maxn],w[maxn]; int dp[maxn][maxn];int main(){cin>>n>>m;for(int i=1;i<=n;i++){cin>>v[i]>>w[i];}memset(dp,0,sizeof(dp));//全部置零 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-1][j-v[i]]+w[i]);}} cout<<dp[n][m]<<endl;}

    空間優化后解法

    空間優化后的ac代碼

    空間優化需要在原來樸素解法的基礎上進行等價變形
    樸素解法是

    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-1][j-v[i]]+w[i]);} }

    現在只需要一維數組dp[maxn],因為本層的結果只與上層的結果有關。
    等價變形的時候去掉第一維,仍然需要和上面兩維邏輯上結果一樣。
    下面來看一下去掉一維之后的結果

    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])dp[j]=max(dp[j],dp[j-v[i]]+w[i]);}}

    第一句dp[j]=dp[j];//相當于dp[i][j]=dp[i-1][j],因為先計算右邊的dp[j],對于第i層而言,這個dp是i-1層的計算結果,也就是滿足dp[i][j]=dp[i-1][j],這個等價可以。

    第二句dp[j]=max(dp[j],dp[j-v[i]]+w[i]);等價于dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);嗎?很遺憾,不等價。為什么?你想啊,等式右邊的dp[j-v[i]]小于等式左邊的dp[j],也就是說,對于第i層而言,dp[j]使用的是本層的dp[j-v[i]],因為從小到大遍歷,當然本層中位于前面的提前計算過。也就是說dp[j]=max(dp[j],dp[j-v[i]]+w[i]);等價于第i層dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i]);
    不是第(i-1)層

    怎么樣才能等價于第i-1層呢?
    可以從大到小遍歷。因為在計算dp[j]的時候,本層的dp[j-v[i]]還沒有算過
    ,此時dp[j-v[i]]使用的是上層的結果
    。即等價于dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);

    for(int i=1;i<=n;i++)for(int j=m;j>=v[i];j--){dp[j]=max(dp[j],dp[j-v[i]]+w[i]);}

    這里遍歷背包容量的時候,需要從大到小遍歷for(int j=m;j>=v[i];j--)

    for(int i=1;i<=n;i++)//遍歷物品for(int j=m;j>=v[i];j--){//遍歷背包容量dp[j]=max(dp[j],dp[j-v[i]]+w[i]);}

    以后寫題,按照這個板子寫。

    #include<iostream> #include<cstring> using namespace std;const int maxn=1e3+10; int n,m; int v[maxn],w[maxn]; int dp[maxn];int main(){cin>>n>>m;for(int i=1;i<=n;i++){cin>>v[i]>>w[i];}memset(dp,0,sizeof(dp));//全部置零 for(int i=1;i<=n;i++)for(int j=m;j>=v[i];j--){dp[j]=max(dp[j],dp[j-v[i]]+w[i]);}cout<<dp[m]<<endl;return 0; }

    總結

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

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