01揹包問題ios
題目算法
有N件物品和一個容量爲M的揹包,每種物品只能夠取一件。第i件物品的費用是c[i],價值是v[i]。求解將哪些物品裝入揹包可以使價值總和最大。數組
分析ide
這是最基礎的揹包問題,特色是:每種物品僅有一件,能夠選擇放或不放。用子問題定義狀態:即f[i][j]表示前i件物品恰放入一個容量爲j的揹包能夠得到的最大價值。則其狀態轉移方程即是:優化
f[i][j]=max{f[i-1][j],f[i-1][j-c[i]]+v[i]}
spa
優化空間複雜度.net
即改用一維數組f[j]存儲第i個物品時剩餘空間爲j時的揹包的最大價值。code
注意到j-c[i]<j這個關係,當j=0……M順序推f[j],則後面的到的f[j]將會使用到當前i狀態下新生成的f[j-c[i]],而不是咱們所需的i-1狀態時的f[j-c[i]]。orm
所以,在每次主循環中咱們以j=M……0順序推f[j],這樣才能保證推f[j]時f[j-c[i]]保存的是狀態f[i-1][j-c[i]]的值。blog
參考代碼
徹底揹包問題
題目
有N件物品和一個容量爲M的揹包,每種物品都有無限件可用。第i件物品的費用是c[i],價值是v[i]。求解將哪些物品裝入揹包可以使價值總和最大。
分析
相似01揹包問題,但與它相關的策略已並不是取或不取兩種,而是有取0件、取1件、取2件……。若是仍然按照解01揹包時的思路,令f[i][j]表示前i種物品恰放入一個容量爲j的揹包的最大權值。仍然能夠按照每種物品不一樣的策略寫出狀態轉移方程:
f[i][j]=max{ f[i-1][j-k*c[i]]+k*v[i] | 0<=k*c[i]<=M }
優化時間複雜度
若兩件物品i、j知足c[i]<=c[j]且w[i]>=w[j],則將物品j去掉,不用考慮。
將費用大於M的物品去掉,而後使用相似計數排序的作法,計算出費用相同的物品中價值最高的是哪一個。
轉化爲01揹包問題求解
最簡單的想法是:考慮到第i種物品最多選M/c[i]件,因而能夠把第i種物品轉化爲M/c[i]件費用及價值均不變的物品,而後求解這個01揹包問題。這樣徹底沒有改進基本思路的時間複雜度,但這畢竟給了咱們將徹底揹包問題轉化爲01揹包問題的思路:將一種物品拆成多件物品。
更高效的轉化方法是:把第i種物品拆成費用爲c[i]*2^k、價值爲v[i]*2^k的若干件物品,其中k知足c[i]*2^k<=M。這是二進制的思想,由於無論最優策略選幾件第i種物品,總能夠表示成若干個2^k件物品的和。這樣把每種物品拆成O(logM/c[i])件物品,是一個很大的改進。
最簡O(MN)算法:首先想一想爲何01揹包問題中爲什麼要按照j=M..0的逆序來循環。這是由於要保證第i次循環中的狀態f[i][j]是由狀態f[i-1][j-c[i]]遞推而來。換句話說,這正是爲了保證每件物品只選一次,保證在考慮「選入第i件物品」這件策略時,依據的是一個絕無已經選入第i件物品的子結果f[i-1][j-c[i]]。而如今徹底揹包的特色恰是每種物品可選無限件,因此在考慮「加選一件第i種物品」這種策略時,卻正須要一個可能已選入第i種物品的子結果f[i][j-c[i]],因此就能夠而且必須採用j=0..M的順序循環。
參考代碼
多重揹包問題
題目
有N件物品和一個容量爲M的揹包,第i種物品最多有n[i]件可用。第i件物品的費用是c[i],價值是v[i]。求解將哪些物品裝入揹包可以使價值總和最大。
分析
這題目和徹底揹包問題很相似。基本的方程只需將徹底揹包問題的方程略微一改便可,由於對於第i種物品有n[i]+1種策略:取0件,取1件……取n[i]件。令f[i][v]表示前i種物品恰放入一個容量爲v的揹包的最大權值,則有狀態轉移方程:
f[i][j]=max{ f[i-1][j-k*c[i]]+k*v[i] | 0<=k<=n[i] }
優化時間複雜度
將第i種物品分紅若干件物品,其中每件物品有一個係數,這件物品的費用和價值均是原來的費用和價值乘以這個係數。使這些係數分別爲1,2,4,...,2^(k-1),n[i]-2^k+1,且k是知足n[i]-2^k+1>0的最大整數。例如,若是n[i]爲13,就將這種物品分紅係數分別爲1,2,4,6的四件物品。
分紅的這幾件物品的係數和爲n[i],代表不可能取多於n[i]件的第i種物品。
參考代碼
題目推薦:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=149
題意:
給出序號爲一、二、三、四、五、6的6種彈珠(好像是彈珠吧⊙﹏⊙b汗),其價值等於其編號,給出每種彈珠的數目,求可否將彈珠分兩堆,使兩堆的價值和相等。
分析:
多重揹包問題,只是所謂的花費cost等於價值,且揹包容量爲總和的一半。
代碼: