設(shè)為首頁收藏本站Access中國

Office中國論壇/Access中國論壇

 找回密碼
 注冊

QQ登錄

只需一步,快速開始

返回列表 發(fā)新帖
查看: 2709|回復(fù): 4
打印 上一主題 下一主題

【算法】【原創(chuàng)】計算總數(shù)是由哪些數(shù)之和

[復(fù)制鏈接]

點擊這里給我發(fā)消息

跳轉(zhuǎn)到指定樓層
1#
發(fā)表于 2015-10-26 10:18:20 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
本帖最后由 盜夢 于 2015-10-26 11:14 編輯

摘要
總有一些財務(wù)的朋友,拿一些數(shù)據(jù)和一個總數(shù)問:這個總數(shù)是哪些數(shù)字之和。
每次我都忍不住要翻白眼。。。
(為什么不問提供這些數(shù)據(jù)的人員呢)

于是,就嘗試用代碼實現(xiàn)這個功能。

算法思路(源碼和附件在后面,不想看思路可以跳過)
假如,現(xiàn)在有一組數(shù)據(jù){1, 2, 3, 4, 5}和一個總數(shù):6。
我想知道這個6可以是哪些數(shù)字之和。
用肉眼很明顯看出 6=2+4 ,6=1+5,6=1+2+3

那么這個就涉及到排列組合中的組合,因為加法交換律,不用考慮數(shù)字的前后順序。
但是,一個總數(shù)可能是一個數(shù)之和,也可能是兩個數(shù)之和。那么就需要判斷一個數(shù)之和到全部數(shù)之和的組合結(jié)果。
例如,
1個數(shù)組合:1,2,3,4,5
2個數(shù)組合:
   1+2,1+3,1+4,1+5
   2+3,2+4,2+5
   3+4,3+5
   4+5
3個數(shù)組合:
   1+2+3,1+2+4,1+2+5
   1+3+4,1+3+5
   1+4+5
   2+3+4,2+3+5
   2+4+5
   3+4+5
4個數(shù)組合:
   1+2+3+4,1+2+3+5
   1+2+4+5
   1+3+4+5
   2+3+4+5
5個數(shù)組合:
   1+2+3+4+5

當然,這么多組合,不可能你一個一個羅列出來。那不得累死。。。
我上面來羅列的時候,是有規(guī)律的,不是隨便寫的。這個就涉及到我如何取數(shù)據(jù)組合的方法了
這種方法我稱之為“末尾移動法”。(不知道有沒重名,自己揣摩出來的)

例如,要在N個數(shù)中取m個數(shù)。
第1次取值,前m個數(shù):N1,N2,...,N(m-1),N(m)
第2次取值,把最后的一個數(shù),往前移動一位:N1,N2,...,N(m-1),N(m+1)
第3次取值,同樣最后一個數(shù)繼續(xù)往前移動:N1,N2,...,N(m-1),N(m+2)
...一直移到不能再移動,也就是最后一個數(shù)
第N-m+1次取值,N1,N2,...,N(m-1),N(N)

最后一個數(shù)移動完成之后,輪到倒數(shù)第二個數(shù)字移動取值。
第N-m+2次取值,N1,N2,...,N(m),N(N)
...同樣一直移到不能再移動為止,如下
第2N-2m+3次取值,N1,N2,...N(N-1),N(N)

接下來,剩下幾個數(shù)輪番處理,直到完成所有組合。
思路看起來有些復(fù)雜,沒辦法,算法就是這樣,哈哈哈

源碼
  1. Option Explicit

  2. '=============================================
  3. '= 函數(shù):計算總數(shù)是由哪些數(shù)之和
  4. '= 作者:阿航
  5. '= 參數(shù):
  6. '=   - arrValue()   數(shù)組     數(shù)據(jù)池
  7. '=   - dblResult    雙精度   總數(shù)
  8. '=   - dblFixed     雙精度   偏差值(誤差值)
  9. '=============================================
  10. Public Function GetCombo(arrValue(), dblResult As Double, Optional dblFixed As Double = 0)
  11.     Dim arrSrc As Long              '元素個數(shù)上限
  12.     Dim arrCalc()                   '計算
  13.     Dim i As Long, iAll As Long     '循環(huán)因子
  14.     Dim iCurrent As Long            '正在變換第幾個元素
  15.     Dim dblSum As Double            '求和
  16.     Dim strExp As String            '輸出表達式
  17.     Dim dblCount As Double          '次數(shù)
  18.    
  19.     arrSrc = UBound(arrValue)
  20.    
  21.     '從1個元素求和到全部元素求和
  22.     For iAll = 0 To arrSrc
  23.         '設(shè)置幾項循環(huán)
  24.         ReDim arrCalc(iAll)
  25.         '初始化
  26.         For i = LBound(arrCalc) To UBound(arrCalc)
  27.             arrCalc(i) = i
  28.         Next i
  29.         
  30.         dblCount = 0    '計數(shù)歸零
  31.         
  32.         Do
  33.             '取值求和
  34.             dblSum = 0
  35.             For i = LBound(arrCalc) To UBound(arrCalc)
  36.                 dblSum = dblSum + arrValue(arrCalc(i))
  37.             Next i
  38.             dblCount = dblCount + 1 '計數(shù)累計
  39.             
  40.             '判斷求和是否正確
  41.             If (dblSum + dblFixed >= dblResult) And (dblSum - dblFixed <= dblResult) Then   '設(shè)置偏差
  42.                 '先輸出結(jié)果
  43.                 strExp = ""
  44.                 For i = LBound(arrCalc) To UBound(arrCalc)
  45.                     strExp = strExp & "+" & arrValue(arrCalc(i))
  46.                 Next i
  47.                 Debug.Print Right(strExp, Len(strExp) - 1) & "=" & dblSum
  48.                 'Exit Function  '得到一次結(jié)果,就退出(可以不先退出,一直計算)
  49.             End If

  50.             '判斷當前循環(huán)數(shù)字
  51.             iCurrent = -1
  52.             For i = UBound(arrCalc) To LBound(arrCalc) Step -1
  53.                 If arrSrc = (UBound(arrCalc) - i) + arrCalc(i) Then
  54.                 Else
  55.                     iCurrent = i
  56.                     Exit For
  57.                 End If
  58.             Next i
  59.             If iCurrent = -1 Then Exit Do   '沒有符合條件的,就是都到頂了

  60.             '當前循環(huán)因子前進一格
  61.             arrCalc(iCurrent) = arrCalc(iCurrent) + 1
  62.             
  63.             '重置后面的循環(huán)因子
  64.             For i = iCurrent + 1 To UBound(arrCalc)
  65.                 arrCalc(i) = arrCalc(i - 1) + 1
  66.             Next i
  67.         Loop
  68.         Debug.Print "完成" & iAll + 1 & "項求和判斷,計算次數(shù):" & dblCount
  69.     Next iAll
  70.     Debug.Print "Compelite"
  71. End Function

  72. '測試,在立即窗口輸入 gTest ,然后敲回車,即可看到測試結(jié)果
  73. Public Function gTest()
  74.     Dim arr()
  75.     arr() = Array(921, 831, 639, 603, 596, 884)
  76.     GetCombo arr, 2156
  77. End Function
復(fù)制代碼
我們測試一下:總數(shù)為2156,數(shù)據(jù)池是{921,831,639,603,596,884}求2156是哪些數(shù)字之和。
在立即窗口輸入 gTest ,然后敲回車


我上面寫的函數(shù)可以設(shè)置誤差值,誤差值為10,可以再得到一個結(jié)果。

附件:

優(yōu)化建議
如果你有更好的取組合方法,可以修改優(yōu)化看看。
另外,如果數(shù)據(jù)池比較多。可以嘗試先用快速排序法,降序排列。
每開始新的取n項組合之前,就判斷第一次之和是否大于等于總數(shù)。如果為假,則不用取n項組合了。


本帖子中包含更多資源

您需要 登錄 才可以下載或查看,沒有帳號?注冊

x
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享分享 分享淘帖 訂閱訂閱

點擊這里給我發(fā)消息

2#
發(fā)表于 2015-10-26 10:19:47 | 只看該作者
強貼!
回復(fù)

使用道具 舉報

3#
發(fā)表于 2015-10-26 10:24:17 | 只看該作者
認真學(xué)習(xí)一下~收藏精品案例~

點擊這里給我發(fā)消息

4#
Debug.Print Right(strExp, Len(strExp) - 1) & "=" & dblSum
打印結(jié)果這里,可以用 Join 方法合并數(shù)組的元素
5#
發(fā)表于 2015-10-26 10:55:37 | 只看該作者
lihai
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則

QQ|站長郵箱|小黑屋|手機版|Office中國/Access中國 ( 粵ICP備10043721號-1 )  

GMT+8, 2025-7-13 21:08 , Processed in 0.085101 second(s), 29 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回復(fù) 返回頂部 返回列表