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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

0-1背包问题(一维数组解法)

發布時間:2025/4/16 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 0-1背包问题(一维数组解法) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

0-1背包問題:?

有N件物品和一個容量為V的背包。第i件物品的費用是c[i],價值是w[i]。求解將哪些物品裝入背包可使這些物品的費用總和不超過背包容量,且價值總和最大。

?這個問題的特點是:每種物品只有一件,可以選擇放或者不放。

算法基本思想:

利用動態規劃思想 ,子問題為:f[i][v]表示前i件物品恰放入一個容量為v的背包可以獲得的最大價值。

其狀態轉移方程是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}??? //這個方程非常重要,基本上所有跟背包相關的問題的方程都是由它衍生出來的。

解釋一下上面的方程:“將前i件物品放入容量為v的背包中”這個子問題,如果只考慮第i件物品放或者不放,那么就可以轉化為只涉及前i-1件物品的問題,即1、如果不放第i件物品,則問題轉化為“前i-1件物品放入容量為v的背包中”;2、如果放第i件物品,則問題轉化為“前i-1件物品放入剩下的容量為v-c[i]的背包中”(此時能獲得的最大價值就是f [i-1][v-c[i]]再加上通過放入第i件物品獲得的價值w[i])。則f[i][v]的值就是1、2中最大的那個值。

(注意:f[i][v]有意義當且僅當存在一個前i件物品的子集,其費用總和為v。所以按照這個方程遞推完畢后,最終的答案并不一定是f[N] [V],而是f[N][0..V]的最大值。)

優化空間復雜度:

以上方法的時間和空間復雜度均為O(N*V),其中時間復雜度基本已經不能再優化了,但空間復雜度卻可以優化到O(V)。

上面f[i][v]使用二維數組存儲的,可以優化為一維數組f[v],將主循環改為:

for i=1..N

for v=V..0

f[v]=max{f[v],f[v-c[i]]+w[i]};

即將第二層循環改為從V..0,逆序。

解釋一下:

假設最大容量M=10,物品個數N=3,物品大小w{3,4,5},物品價值p{4,5,6}。

當進行第i次循環時,f[v]中保存的是上次循環產生的結果,即第i-1次循環的結果(i>=1)。所以f[v]=max{f[v],f[v-c[i]]+w[i]}這個式子中,等號右邊的f[v]和f[v-c[i]]+w[i]都是前一次循環產生的值。

當i=1時,f[0..10]初始值都為0。所以

f[10]=max{f[10],f[10-c[1]]+w[1]}=max{0,f[7]+4}=max{0,0+4}=4;

f[9]=max{f[9],f[9-c[1]]+w[1]}=max{0,f[6]+4}=max{0,0+4}=4;

......

f[3]=max{f[3],f[3-c[1]]+w[1]}=max{0,f[3]+4}=max{0,0+4}=4;

f[2]=max{f[2],f[2-c[1]]+w[1]}=max{0,f[2-3]+4}=0;//數組越界?

f[1]=0;

f[0]=0;

當i=2時,此時f[0..10]經過上次循環后,都已經被重新賦值,即f[0..2]=0,f[3..10]=4。利用f[v]=max{f[v],f[v-c[i]]+w[i]}這個公式計算i=2時的f[0..10]的值。

當i=3時同理。

具體的值如下表所示:

因此,利用逆序循環就可以保證在計算f[v]時,公式f[v]=max{f[v],f[v-c[i]]+w[i]}中等號右邊的f[v]和f[v-c[i]]+w[i]保存的是f[i-1][v]和f[i -1][v-c[i]]的值。

當i=N時,得到的f[V]即為要求的最優值。

初始化的細節問題:

?在求最優解的背包問題中,一般有兩種不同的問法:1、要求“恰好裝滿背包”時的最優解;2、求小于等于背包容量的最優解,即不一定恰好裝滿背包。

這兩種問法,在初始化的時候是不同的。

1、要求“恰好裝滿背包”時的最優解:

在初始化時除了f[0]為0其它f[1..V]均設為-∞,這樣就可以保證最終得到的f[N]是一種恰好裝滿背包的最優解。如果不能恰好滿足背包容量,即不能得到f[V]的最優值,則此時f[V]=-∞,這樣就能表示沒有找到恰好滿足背包容量的最優值。

2、求小于等于背包容量的最優解,即不一定恰好裝滿背包:

如果并沒有要求必須把背包裝滿,而是只希望價值盡量大,初始化時應該將f[0..V]全部設為0

總結

01背包問題是最基本的背包問題,它包含了背包問題中設計狀態、方程的最基本思想,另外,別的類型的背包問題往往也可以轉換成01背包問題求解。故一定要仔細體會上面基本思路的得出方法,狀態轉移方程的意義,以及最后怎樣優化的空間復雜度。

代碼1#include <iostream> #include <vector> using namespace std; const int MIN=0x80000000; const int N=3; //物品數量 const int V=5; //背包容量 int f[N+1][V+1];int Package(int *W,int *C,int N,int V); void main(int argc,char *argv[]) {int W[4]={0,7,5,8}; //物品權重int C[4]={0,2,3,4}; //物品大小int result=Package(W,C,N,V);if(result>0){cout<<endl;cout<<"the opt value:"<<result<<endl;int i=N,j=V;while(i){if(f[i][j]==(f[i-1][j-C[i]]+W[i])){cout<<i<<":"<<"w="<<W[i]<<",c="<<C[i]<<endl;j-=C[i];}i--;}}elsecout<<"can not find the opt value"<<endl;return; }int Package(int *W,int *C,int N,int V) {int i,j;memset(f,0,sizeof(f)); //初始化為0for(i=0;i<=N;i++)for(j=1;j<=V;j++) //此步驟是解決是否恰好滿足背包容量,f[i][j]=MIN; //若“恰好”滿足背包容量,即正好裝滿背包,則加上此步驟,若不需要“恰好”,則初始化為0for(i=1;i<=N;i++)for(j=C[i];j<=V;j++){f[i][j]=(f[i-1][j]>f[i-1][j-C[i]]+W[i])?f[i-1][j]:(f[i-1][j-C[i]]+W[i]);cout<<"f["<<i<<"]["<<j<<"]="<<f[i][j]<<endl;}return f[N][V]; } 代碼2#include <iostream> #include <vector> using namespace std; const int MIN=0x80000000; const int N=3; //物品數量 const int V=5; //背包容量 int f[V+1];int Package(int *W,int *C,int N,int V); void main(int argc,char *argv[]) {int W[4]={0,7,5,8}; //物品權重int C[4]={0,2,3,4}; //物品大小int result=Package(W,C,N,V);if(result>0){cout<<endl;cout<<"the opt value:"<<result<<endl;}elsecout<<"can not find the opt value"<<endl;return; }int Package(int *W,int *C,int N,int V) {int i,j;memset(f,0,sizeof(f)); //初始化為0for(i=1;i<=V;i++) //此步驟是解決是否恰好滿足背包容量,f[i]=MIN; //若“恰好”滿足背包容量,即正好裝滿背包,則加上此步驟,若不需要“恰好”,則初始化為0for(i=1;i<=N;i++)for(j=V;j>=C[i];j--) //注意此處與解法一是順序不同的,弄清原因{f[j]=(f[j]>f[j-C[i]]+W[i])?f[j]:(f[j-C[i]]+W[i]);cout<<"f["<<i<<"]["<<j<<"]="<<f[j]<<endl;}return f[V]; }


總結

以上是生活随笔為你收集整理的0-1背包问题(一维数组解法)的全部內容,希望文章能夠幫你解決所遇到的問題。

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