2013-07-26 49 views
0

我需要找到列表中的號碼,從而彌補了具體的總:如何找出哪個小計組成一個總和?

Sum: 500 

Subtotals: 10 490 20 5 5 

In the end I need: {10 490, 490 5 5} 

你怎麼稱呼這種類型的問題?有算法來有效地解決它嗎?

+4

你嘗試過什麼嗎? – stan0

+5

看起來像是http://en.wikipedia.org/wiki/Subset_sum_problem。 – hivert

+0

我目前正在審閱這篇文章:http://en.wikipedia.org/wiki/Partition_(number_theory) – Kiril

回答

3

這是Knapsack problem,它是一個NP完全問題,即沒有一個已知的有效算法。

1
  1. 這是不是一個揹包問題。
  2. 在最壞的情況下,對於N個小計,可以有O(2^N)個解,所以任何算法在最壞情況下都不會比這更好(因此,問題根本不屬於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.如果問題的大小足夠小,您也可以考慮動態編程:

  1. 以集合{0}開始。創建大小等於小計數組的數組集合。
  2. 對於每個小計,通過添加小計值,從以前的設置創建一個新集。刪除大於Sum的所有元素。將它與前一集合並(它將基本上是所有可能的總和)。
  3. 如果在最後一組沒有和,那麼就沒有解決方案。否則,您將解決方案從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}。

+0

我無法從根本上理解您的解決方案,但我確定原始問題是揹包問題。對於原始列表中的n個元素,這些元素的子集有2 n,您需要確定那些元素的總和恰好是給定的整數。找到一個這樣的子集已經是Knapsack。要枚舉所有這些問題並不容易。 –

+0

首先:揹包問題需要兩組數字,權重和成本。第二:揹包問題是關於是否存在一個適合揹包的佈局,並且花費比給定的更多。因此,揹包問題的假設解決方案不能簡單地轉化爲解決這個問題的方法,它們是不同的問題。第三:揹包問題是NP完全的,這意味着它與SAT問題「等價」。 Kiril提出的問題是**不是** NP,因爲在最壞的情況下,它不能在多項式時間內解決(輸出非多項式大小)。 – Abstraction

+0

請看http://en.wikipedia.org/wiki/List_of_knapsack_problems#Direct_generalizations。在那裏列出了權重等於成本的情況,並註明「如果對於每個項目,利潤和權重是相同的,我們得到子集和問題。」子集問題也是NP完全的。是的,列舉任何可能成倍增長的問題的所有解決方案在NP中都不是問題。當我寫「這是一個揹包問題」時,我正在簡化。我想我應該寫下「決策版本已經是一個類似揹包的NP完全問題,通常稱爲子集總和」。 –

相關問題