子集合加總問題(Subset sum problem)

兩年前在作一個ERP項目時,有個客戶提出,根據訂單給出的每一個貨品的數量(庫裏存的有每一個貨品最小包裝的重量,體積和長寬高),輸入包裝箱的承重和體積和長寬高,而後我須要大家提供一個包裝方案,要求結果是用最少的紙箱來包裝這些貨物並給出包裝步驟,最好能用3D圖表示。當時我就蒙了,這算法要是靠外包公司寫,不知道寫不寫的出來,因而給客戶扯了個相似的揹包問題,而後告訴它這是NP徹底問題,很是複雜,貨物不少的時候你的服務器不必定能承受計算的壓力。而後客戶也蒙了,再而後這個需求就取消了。其實,這個究竟是不是揹包問題,是否是屬於NP徹底問題,我也不敢講,沒仔細的推導過。當時只是以爲場景相似,因此就舉了個這樣的例子給他。如今得回顧一下這個問題,看看靠本身得知識能不能把這個問題推導至揹包問題。可是要說揹包問題,仍是先說子集合加總問題吧。
程序員


給一個整數集合,問是否存在某個非空子集,使得子集內中的數字和爲0?例:給定集合{−7, −3, −2, 5, 8},答案是存在,由於子集{−3, −2, 5}的數字和是0。這個問題被證實是屬於NP徹底問題。若是把這個問題看成一個特例,那範圍更廣的問題就是 「給一個整數集合A,問是否存在某個非空子集s,使得子集內中的數字和爲B」 ,當咱們把B設爲0時,就是咱們上面的那個問題了。而第二個問題,屬於揹包問題的一個特例。
算法

子集特定合問題的最簡單算法(把全部的子集所有列出來,而後對每個子集作運算)時間複雜度是(2N),由於有2N個非空子集,而後對於每個子集,咱們最多會作N次加法運算。數組

有人搞出另一個算法,這個算法的時間複雜度是(2N/2 )  (Horowitz and Sahni ,1972服務器

對他們在1972年提出的這個算法的簡單解釋以下,學習

將任意給定元素的集合N分紅平分紅兩個集合,每一個集合有N/2個元素,而後計算出每一個集合的子集的和加總結果,得出兩個列表,對這兩個列表用比較排序法,而後咱們再把兩個列表的元素相加,看是否有其中一對能獲得要求的結果。這個加法運算是從第一個列表的頭和第二個列表的尾開始。spa


經過動態規劃,還能搞出一個僞多項式時間複雜度的算法,對於斷定是否有子集和爲0的算法的大概的解釋是排序

序列爲 x1, ..., xn遞歸

A爲集合中正數的總和it

B爲集合中負數的總和基礎

一個方法Q(i, s) 輸出是否有子集(x1, ..., xi )的和等於s。

當s=0時,這個方法給出的結果時子集i的和是否等於0

那很明顯,當s < A 或者 s > B 時 ,Q(i, s)輸出否,也就是兩個集合不符合這個條件的均可以不被計算和存儲。

構造一個數組來保存符合1 ≤ i ≤ N 和 A ≤ s ≤ B Q(i,s )結果。

遞歸的把結果放到這個數組中,當i=1 , A ≤ s ≤ 

Q(1,s) := (x1 == s)

當i >1時

(,s) := i  − 1, sor (xi == sor i  − 1, s − xi)   for A ≤ s ≤ B

當咱們每次往數組中插入值的時候,咱們都已知Q的值,因此最終算法的時間複雜度是 − ) ). 也就是當計算全部的值的時間複雜度是(k),總體算法的複雜度是k+2) ,可是由於A,B值的大小問題,這個算法不符合時間複雜度理論的多項式算法。


Wiki上面還有個線性時間的相似問題的算法,有些改動,可是那個須要時間參透,本身都沒太看明白的東西仍是不要擺出來了。


小總結,研究這些問題,或者,學習這些問題的分析方法和分析思路是很是有好處的,作爲一個什麼都乾的程序員,和客戶談需求的時候必需要掌握一些問題的類型,或者能快速的將客戶的問題概括到某個已被證實複雜度的問題上(每每客戶提出的問題都是這類問題的某個特例),如此纔可有理由的答應或者拒絕客戶提出的需求。並且,在處理問題的時候,也能快速的想出比較合適的算法來實現某些功能。總之,要想提升代碼的質量和水平,基礎仍是要紮實的學的。

相關文章
相關標籤/搜索