今天賢內給了我一道很實際的演算法題,把我徹底難住了,實在想不出來,於是寫此博文以記之。
背景是這樣的,現在有一個付款明細的Excel,裡面有為哪個發票,哪個公司應付多少錢的明細,明細資料是62條,現在知道我們已經付出的金額為Sum,請問到底哪些發票是已付款的。
這是62條明細資料:
653165.00 |
356029.11 |
220896.45 |
146362.00 |
1847670.00 |
3018518.91 |
1347553.07 |
145010.74 |
339784.84 |
199350.28 |
1206114.00 |
882000.00 |
253246.13 |
720000.00 |
24194.07 |
1518952.00 |
139453.48 |
200415.00 |
812044.00 |
9032764.57 |
3960608.05 |
1855126.31 |
7409087.18 |
608094.66 |
225519.59 |
627912.23 |
109897.52 |
1215819.87 |
4220245.50 |
94299.00 |
96547.00 |
92616.01 |
597100.54 |
880440.00 |
343991.59 |
70468.19 |
1092418.47 |
66911.94 |
80138.65 |
1398551.14 |
172287.48 |
691097.86 |
2371693.44 |
3773148.63 |
83898.33 |
89922.75 |
2619220.46 |
1179477.63 |
3440250.98 |
700000.00 |
997545.00 |
272523.00 |
3009976.00 |
451891.44 |
2111314.00 |
306377.00 |
142329.00 |
2057178.00 |
9340.00 |
249027.00 |
60811.50 |
51188.50 |
付款的金額為:
35857936.42
這聽起來是一個很簡單的演算法題,其實就是算組合嘛,把每種組合的金額進行相加,如果等於Sum金額,那麼就輸出這種組合。於是網上找找組合函式的程式碼,很快就寫出了這個程式。而且使用了一些簡單的測試程式,確認計算是正確的。但是真正用到這個事情中,卻崩潰了,計算量太大,根本算不出來。
仔細一想,對於每個數字,要麼出現,要麼不出現,那麼其計算複雜度就是O(2^n),這裡n=62,那麼差不多就得計算2的62次,遍歷每一種組合,才能找到全部答案。天啊!2的62次方!
根本不可能完成啊。想了又想,怎麼都沒有想到好的辦法把複雜度降下來,傷心。不知道有沒有大神能夠解決這個問題。
這還只是一次資料,以後說不定還有100條明細,200條明細的,就這破演算法,那更是天文數字,怎麼可能算得出來啊?!
附上現有的程式碼下載。
更新:
好吧,看來我太無知了,這個問題是沒有解決辦法的,StackOverflow的討論:http://stackoverflow.com/questions/4355955/subset-sum-algorithm
而且還有專門的維基百科頁面:http://en.wikipedia.org/wiki/Subset_sum_problem#Pseudo-polynomial_time_dynamic_programming_solution