至少有4種揹包問題:1)01揹包 2) 部分揹包 3)完全揹包 4)多重揹包。只有部分揹包是個貪心問題,其他的都是以01揹包為基礎的動歸問題。
部分揹包問題:
把物品按價值密度從大到小排序(w[i]/v[i]),然後從第一種物品開始,盡可能多拿當前物品,如果當前物品的量小於揹包剩餘容量,拿完,指標推到下一種物品;否則拿揹包剩餘容量的量,結束。
01揹包問題
遞推式:f(i,j )= max ( f(i-1, j), f(i-1, j-v[i])+w[i]),i定義為前i個物品,j為當前揹包剩餘容量。當前狀態只跟上一行相同列和乙個前面的列有關,滾動陣列逆序求解。滾動陣列初始值代表拿0個物品,不管揹包容量是多少價值都是0,所以初始化全是0,行迴圈下界從1開始。列的計算也是從1開始,因為第0列代表容量為零,乙個物品都放不下,價值必然是0,進一步的優化是從v[i]開始,因為揹包容量小於v[i]的時候,當前物品i必然沒辦法拿,只能是f(i-1, j) 即保持上一行的狀態。複雜度分析:二維動歸,狀態是二維的,遍歷所有狀態是o(n*c),計算每個狀態的開銷是o(1),總的複雜度是o(n*c)。
完全揹包問題
每個物品不是取還是不取,而是可以取任意次數。
思路1:雖說可以取任意次,實際上每個物品可取的次數有個上限,即c/v[i]。乙個物品可拿c/v[i]次可以分割為c/v[i]個只能拿一次的相同物品,轉換為0,1揹包。o(n' *c)
思路2:直接擴充套件0,1揹包的思路,從2種選擇(0,1)擴充套件到 c/v[i]種選擇(0,1,2,...c/v[i])。遞推式:f(i,j) = max k=0,1,.., c/v[i]。滾動陣列依然是逆序求解。複雜度分析:遍歷二維狀態 是o(n*c),計算每個狀態是o(c/v[i]),總得複雜度是o(nc*c/v[i])
思路3:遞推式:f(i, j) = max ( f(i-1, j), f(i, j - v[i]) + w[i]) 這個遞推式和01揹包的遞推式很像,只是max裡的第二項是本行的狀態。遞推式的含義不是按當前物品拿幾次劃分,而是另一種劃分和解釋:用前i-1個物品裝容量j的最大價值,和用前i個物品,先裝最大 j- v[i]的容量,然後再裝乙個物品i的價值,二者的大者。劃分的角度是用不用到前i個物品。注意這裡f的定義和01揹包就不同:f(i,j)的定義是,用前i個物品,每個物品不限次數,裝到容量為j的揹包的最大價值。滾動陣列求解是正序的。正序和逆序的區別就是,對於正序,j以前的狀態是當前行的狀態;對於逆序,j以前的狀態是上乙個行的狀態。複雜度分析:遍歷二維狀態o(n*c),計算狀態o(1),總的複雜度是o(n*c)。
思路4:直接遞迴的思路。考察在裝任意乙個物品之後面臨的問題,仍然可以從n中物品中任意選擇,這個條件沒有變化,只是揹包容量變小了,也就是說裝了任意乙個物品之後的面臨的問題是和原問題相同的問題,只是規模變小了,這就是遞迴。而且僅僅是揹包容量這乙個維度變小了,是一維遞迴。反觀01揹包,在裝乙個物品之後面臨的問題,不僅僅是原問題揹包容量變小之後的子問題,因為問題其他條件也變了,有乙個物品不能選了,必須把這個變數也作為遞迴變數,是二維遞迴。直接遞迴法下的完全揹包問題遞推式:f(j) = max , i= 1,..., n and v[i]<=c 。解釋是,先取乙個,然後解決剩下的問題,經典的遞迴、分治思想,先讓規模減小一步,然後解決規模變小了的相同問題。
多重揹包問題
每個物品取的次數有限制,輸入多乙個陣列num[n]。
思路1:次數轉化成物品數,變成01揹包問題。
思路2:擴充套件01揹包問題,第i個物品分別拿0到num[i]次,還要滿足j-num[i] * v[i]>0
揹包問題變種:硬幣問題
其實01揹包問題的模型是相對複雜的,輸入是一兩個陣列,乙個cost陣列,乙個價值陣列,還有乙個總cost上限,求價值最大化的值。
變種1:最少硬幣問題。給定乙個硬幣面額集合和乙個金額,求最怎樣用最少的硬幣湊成這個金額?輸入比揹包問題少乙個陣列,問題不如揹包問題複雜。用揹包問題的元素翻譯一下:給定一組物體的體積,求裝滿乙個給定容量揹包所用物品的最少個數,每個物品可以任意取。
遞推式:f( j) = min i= 1,.., n and v[i-1]<= j,先分別取乙個每乙個可以取的硬幣(面額小於給定的金額),然後遞迴解決金額變小了的子問題,得到分別先取每乙個硬幣的取法的最小硬幣數,然後取最小的。
思路2:完全揹包,f(i, j) = min( f(i-1, j), f(i, j - v[i-1]))
變種2:方案數問題,給定乙個硬幣面額集合和乙個金額,求用這面額的硬幣湊成這個金額的方案數。
遞迴思路:完全揹包:不取第i種面額的方案數+ 取第i種面額的方案數。遞推式:f(i, j) = f(i-1, j) + f(i, j - v[i - 1])
變種3:給定n種硬幣,從中取k個,求方案數。
多重揹包問題 硬幣
給定n種硬幣,其中第 i 種硬幣的面值為ai,共有ci個。從中選出若干個硬幣,把面值相加,若結果為s,則稱 面值s能被拼成 求1 m之間能被拼成的面值有多少個。輸入格式 輸入包含多組測試用例。每組測試用例第一行包含兩個整數n和m。第二行包含2n個整數,分別表示a1,a2,an和c1,c2,cn。當輸...
最少硬幣問題(多重揹包)
time limit 1000 ms memory limit 65536 kib submit statistic problem description 設有n種不同面值的硬幣,各硬幣的面值存於陣列t 1 n 中。現要用這些面值的硬幣來找錢。可以使用的各種面值的硬幣個數存於陣列coins 1 n...
找換硬幣問題 與 0 1揹包問題區別
之所以再寫一篇blog,是因為現實中很多問題都可以轉化成 找換硬幣 問題 和 0 1 揹包問題。因此,需要細細理解。其次,在 參考資料 中彙總關於 貪心演算法與動態規劃的一些blog及學習資料。區別 其實最大的區別就是 找換硬幣問題中的 某類硬幣 是可以多次選擇的。而對於0 1揹包問題,某物品要麼選...