我需要找到列表中的號碼,從而彌補了具體的總:如何找出哪個小計組成一個總和?
Sum: 500
Subtotals: 10 490 20 5 5
In the end I need: {10 490, 490 5 5}
你怎麼稱呼這種類型的問題?有算法來有效地解決它嗎?
我需要找到列表中的號碼,從而彌補了具體的總:如何找出哪個小計組成一個總和?
Sum: 500
Subtotals: 10 490 20 5 5
In the end I need: {10 490, 490 5 5}
你怎麼稱呼這種類型的問題?有算法來有效地解決它嗎?
這是Knapsack problem,它是一個NP完全問題,即沒有一個已知的有效算法。
我們假設Subtotals數組中沒有非正數元素,並且任何元素都不超過Sum。我們可以對小數數組進行排序,然後構建數組尾數,並在末尾加上0。在你的榜樣,它看起來像:
Subtotals: (490, 20, 10, 5, 5)
PartialSums: (530, 40, 20, 10, 5, 0)
現在對於任何 「餘額」 S,我的位置, 「當前列表」 L我們有問題,E(S,I,L):
E( 0,i,L)=(打印L)。 (S,i,L)|
E(S,i,L)| (PartialSums [i] < S)=(無)。 (S,i + 1,L),E(S-Subtotals [i],j,L || Subtotals [i]),其中j是第一元素的索引小計小於或等於(S-小計[i])或i + 1,以較大者爲準。
我們的問題是E(Sum,0,{})。
當然,重複出現問題(如果列表中有另外490個數字,此算法將輸出4個解決方案)。如果這不是你所需要的,使用數組對(value,multiplicity)可能會有所幫助。
P.S.如果問題的大小足夠小,您也可以考慮動態編程:
如果在最後一組沒有和,那麼就沒有解決方案。否則,您將解決方案從Sum回溯到0,檢查前一個集合是否包含[value]和[value-subtotal]。
實施例:
(10,490,20,5,5)
集:
(0)
(0, 10)
(0, 10, 490, 500)
(0, 10, 20, 30, 490, 500) (510, 520 - discarded)
(0, 5, 10, 15, 20, 25, 30, 35, 490, 495, 500)
(0, 5, 10, 15, 20, 25, 30, 35, 40, 490, 495, 500)
從最後一組:[500-5]在前面的組,[495 -5],[490-20]不在先前的集合([490]是),[490-490]爲0,結果爲{5,5,490}。
我無法從根本上理解您的解決方案,但我確定原始問題是揹包問題。對於原始列表中的n個元素,這些元素的子集有2 n,您需要確定那些元素的總和恰好是給定的整數。找到一個這樣的子集已經是Knapsack。要枚舉所有這些問題並不容易。 –
首先:揹包問題需要兩組數字,權重和成本。第二:揹包問題是關於是否存在一個適合揹包的佈局,並且花費比給定的更多。因此,揹包問題的假設解決方案不能簡單地轉化爲解決這個問題的方法,它們是不同的問題。第三:揹包問題是NP完全的,這意味着它與SAT問題「等價」。 Kiril提出的問題是**不是** NP,因爲在最壞的情況下,它不能在多項式時間內解決(輸出非多項式大小)。 – Abstraction
請看http://en.wikipedia.org/wiki/List_of_knapsack_problems#Direct_generalizations。在那裏列出了權重等於成本的情況,並註明「如果對於每個項目,利潤和權重是相同的,我們得到子集和問題。」子集問題也是NP完全的。是的,列舉任何可能成倍增長的問題的所有解決方案在NP中都不是問題。當我寫「這是一個揹包問題」時,我正在簡化。我想我應該寫下「決策版本已經是一個類似揹包的NP完全問題,通常稱爲子集總和」。 –
你嘗試過什麼嗎? – stan0
看起來像是http://en.wikipedia.org/wiki/Subset_sum_problem。 – hivert
我目前正在審閱這篇文章:http://en.wikipedia.org/wiki/Partition_(number_theory) – Kiril