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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

动态规划(2.2)背包问题扩展

發布時間:2023/12/20 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动态规划(2.2)背包问题扩展 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

一、對體積的限制

(1)體積不大于

(2)體積恰好等于

(3)體積至少為

二、分組背包問題拓展

(1)Acwing 487

(2)背包問題結合樹、dfs(有依賴的背包問題)

三、混合背包問題

四、背包問題求最優方案數

五、背包問題結合貪心


一、對體積的限制

參考文章https://www.acwing.com/file_system/file/content/whole/index/content/1306630/

求方案數初始化?

二維情況:

  • 體積至多j,f(0,i)=1,i=0~m,其余是0。
  • 體積恰好j,f(0,0)=1,其余是0。
  • 體積至少j,f(0,0)=1,其余是0。

一維情況:

  • 體積至多j,f(i)=1,i=0~m。
  • 體積恰好j,f(0)=1,其余是0.
  • 體積至少j,f(0)=1,其余是0

求最大最小值初始化總結

二維情況:

  • 體積至多j,f(i,k)=0,i=0~n,k=0~m。(只能求最大值)
  • 體積恰好j,
    • 求價值最大值:f(0,0)=0,其余-INF
    • 求價值最小值:f(0,0)=0,其余INF(只會從0,0與物品的體積和價值,特定的更新某些值)
  • ? 體積至少j,f(0,0)=0,其余INF。(只能求最小值)

一維情況:

  • 體積至多j,f全為0
  • 體積恰好j,
    • 求價值最大值,f(0)=0,其余-INF
    • 求價值最小值,f(0)=0,其余INF
  • 體積至少j,f(0)=0,其余INF

下面展示部分求價值最大值時,體積恰好j,體積至少j的代碼,注意觀察循環體內寫法區別和意,求體積至多j的問題不再贅述。

01背包體積恰好j

#include <iostream> #include <cstring>using namespace std;const int N = 110, INF = 0x3f3f3f3f;int n, m; int f[N];int main() {cin >> n >> m;memset(f, -INF, sizeof f);f[0] = 0;for(int i = 1;i <= n;i ++){int v, w;cin >> v >> w;for(int j = m;j >= v;j --){f[j] = max(f[j], f[j - v] + w);}}cout << f[m] << endl;return 0; }作者:小呆呆 鏈接:https://www.acwing.com/file_system/file/content/whole/index/content/1306630/ 來源:AcWing 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

完全背包恰好j

#include <iostream> #include <cstring>using namespace std;const int N = 110, INF = 0x3f3f3f3f;int n, m; int f[N];int main() {cin >> n >> m;memset(f, -INF, sizeof f);f[0] = 0;for(int i = 1;i <= n;i ++){int v, w;cin >> v >> w;for(int j = v;j <= m;j ++){f[j] = max(f[j], f[j - v] + w);}}cout << f[m] << endl;return 0; }作者:小呆呆 鏈接:https://www.acwing.com/file_system/file/content/whole/index/content/1306630/ 來源:AcWing 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

01背包至少j(只能求價值最小值)

不同點:恰好是j問題時,控制了j-v>=0,因為小于0的狀態不存在,不可能由他們更新其它狀態。而至少是j問題時,j-v<0的狀態是合法的,等價于j-v==0,因此j層循環要遍歷0~m,第二維狀態寫法為max(0,j-v)。

#include <iostream> #include <cstring>using namespace std;const int N = 110, INF = 0x3f3f3f3f;int n, m; int f[N];int main() {cin >> n >> m;memset(f, INF, sizeof f);f[0] = 0;for(int i = 1;i <= n;i ++){int v, w;cin >> v >> w;for(int j = m;j >= 0;j --){f[j] = min(f[j], f[max(0, j - v)] + w);//即使物品體積比j大,j - v < 0,也能選,等價于f[0]}}cout << f[m] << endl;return 0; }作者:小呆呆 鏈接:https://www.acwing.com/file_system/file/content/whole/index/content/1306630/ 來源:AcWing 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

?完全背包至少j(只能求價值最小值)

#include <iostream> #include <cstring>using namespace std;const int N = 110, INF = 0x3f3f3f3f;int n, m; int f[N];int main() {cin >> n >> m;memset(f, INF, sizeof f);f[0] = 0;for(int i = 1;i <= n;i ++){int v, w;cin >> v >> w;for(int j = 0;j <= m;j ++){f[j] = min(f[j], f[max(0, j - v)] + w);//即使物品體積比j大,j - v < 0,也能選,等價于f[0]}}cout << f[m] << endl;return 0; }

二、分組背包問題拓展

(1)Acwing 487

?題目要求:要選擇附件就必需選擇主件。因此我們可以把每一個主件看成一個組,將不選擇、選擇1個附件、兩個附件、、k個附件打包看做背包中的物品,則問題轉化為分組背包問題。每組分為不選擇,選擇主和Cn0個附+Cn1個附+....共2^n種情況。

表示:可以用二進制數來表示打包的方案。例如:1010表示選擇了第2個、第4個附件和主件。

#include<iostream> #include<algorithm> #include<cstring>//每組分為不選擇,選擇主和Cn0個附+Cn1個附+....共2^n種情況,轉化為分組背包問題 using namespace std; const int N =70,M=32010;typedef pair<int,int> PII;PII master[N]; int n,m; int f[M]; vector<PII> servent[N];int main() {cin>>m>>n;for(int i=1;i<=n;i++){int v,w,q;cin>>v>>w>>q;if(!q) master[i]={v,v*w};else servent[q].push_back({v,v*w});}for(int i=1;i<=n;i++){if(master[i].first){for(int j=m;j>=0;j--){auto& sv=servent[i];for(int k=0;k<1<<sv.size();k++){int v=master[i].first,w=master[i].second;for(int u=0;u<sv.size();u++)if(k>>u&1){v+=sv[u].first;w+=sv[u].second;}if(j>=v) f[j]=max(f[j],f[j-v]+w);}}}}cout<<f[m];}作者:yankai 鏈接:https://www.acwing.com/activity/content/code/content/4118462/ 來源:AcWing 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

(2)背包問題結合樹、dfs(有依賴的背包問題)

三、混合背包問題

?綜合一下之前學過的,發現狀態轉移方程只和第i層的物品有關,和之前的物品種類無關。因此狀態更新時用對應的轉移方程即可。(這里用了一下代碼簡化版的2進制拆分解多重背包問題)

#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N =1010;int f[N]; int n,m; //每種物品根據每種問題的狀態轉移方程做就可以,狀態轉移方程是獨立的,不會因為其他物品的種類變化 int main() {cin>>n>>m;for(int i=1;i<=n;i++){int v,w,s;cin>>v>>w>>s;if(s==0){for(int j=v;j<=m;j++)f[j]=max(f[j],f[j-v]+w);}else{if(s==-1) s=1;for(int k=1;k<=s;k*=2){for(int j=m;j>=k*v;j--)f[j]=max(f[j],f[j-k*v]+k*w);s-=k;}if(s){for(int j=m;j>=s*v;j--)f[j]=max(f[j],f[j-s*v]+s*w);}}}cout<<f[m];return 0; }作者:yankai 鏈接:https://www.acwing.com/activity/content/code/content/4118828/ 來源:AcWing 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

四、背包問題求最優方案數

狀態表示為體積恰好是j時,f表示最優方案的取值,g表示最優方案的數量。

f的狀態轉移方程不再贅述,g的狀態轉移方程分為兩部分,不選第i件物品與選擇第i件物品。如果不選是最優解,則g[j]=g[j],如果選第i件物品是最優解,則g[j]=g[j-v],如果兩者相等,則g[j]=g[j]+g[j-v]。

最后遍歷f求得全局最優解的值,然后遍歷g,求得全局最優解方案的數量

#include<iostream> #include<algorithm> #include<cstring> using namespace std;const int N =1010,mod=1e9+7;int f[N],g[N]; int n,m;int main() {cin>>n>>m;//狀態表示為體積恰好是jmemset(f,0xcf,sizeof f);f[0]=0;g[0]=1;for(int i=1;i<=n;i++){int v,w;cin>>v>>w;for(int j=m;j>=v;j--){int cnt=0;int maxv=max(f[j],f[j-v]+w);if(maxv==f[j]) cnt+=g[j];if(maxv==f[j-v]+w) cnt+=g[j-v];g[j]=cnt%mod;f[j]=maxv;}}int res=0;//由于狀態表示是恰好,所以要遍歷求出最優方案所得的值,然后再求最優方案出現的次數for(int i=0;i<=m;i++) res=max(res,f[i]);int cnt=0;for(int i=0;i<=m;i++)if(res==f[i])cnt=(cnt+g[i])%mod;cout<<cnt;return 0; }作者:yankai 鏈接:https://www.acwing.com/activity/content/code/content/4119420/ 來源:AcWing 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

五、背包問題結合貪心

?

直覺發現,如果前面吃能量石用過多時間,后面能量就會流失嚴重,因此選擇時應該遵循某種順序選擇。

接下來假設有i,j兩塊能量石,探討一下根據什么順序選擇。

如果按i,j順序吃:

如果按j,i順序吃:

因此選擇順序由s/l決定,s/l越小,后面能量流失就越小。

按s/l排序后,轉化為01背包問題

為了計算損失的能量,狀態表示為體積恰好等于j,狀態轉移方程為:

#include<iostream> #include<algorithm> #include<cstring> using namespace std;const int N =1010,mod=1e9+7;int f[N],g[N]; int n,m;int main() {cin>>n>>m;//狀態表示為體積恰好是jmemset(f,0xcf,sizeof f);f[0]=0;g[0]=1;for(int i=1;i<=n;i++){int v,w;cin>>v>>w;for(int j=m;j>=v;j--){int cnt=0;int maxv=max(f[j],f[j-v]+w);if(maxv==f[j]) cnt+=g[j];if(maxv==f[j-v]+w) cnt+=g[j-v];g[j]=cnt%mod;f[j]=maxv;}}int res=0;//由于狀態表示是恰好,所以要遍歷求出最優方案所得的值,然后再求最優方案出現的次數for(int i=0;i<=m;i++) res=max(res,f[i]);int cnt=0;for(int i=0;i<=m;i++)if(res==f[i])cnt=(cnt+g[i])%mod;cout<<cnt;return 0; }作者:yankai 鏈接:https://www.acwing.com/activity/content/code/content/4119420/ 來源:AcWing 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

?

總結

以上是生活随笔為你收集整理的动态规划(2.2)背包问题扩展的全部內容,希望文章能夠幫你解決所遇到的問題。

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