Excel中背包的变化

时间:2017-06-13 13:54:41

标签: excel vba solver knapsack-problem

所以,我需要找到10个数据点列表的组合总数,这些数据点加起来至少为100个。所有解决这个问题的例子我发现只给出EQUAL数字的组合数量。如何计算高于100的组合?如果没有Excel中的VBA,这可行吗?

另一个想法是计算组合总数(10!)并减去1,000以下的组合来查找数字。但同样,如何找到落在某个范围内的组合总数?

问题陈述:10个数据点(65,52,48,44,42,41,39,38,30,18)总共至少有100个组合?

我尝试过的来源(我不能发布2个以上的链接) http://www.tushar-mehta.com/excel/templates/match_values/index.html

Find out which combinations of numbers in a set add up to a given total

2 个答案:

答案 0 :(得分:3)

  1. 通过 J1
  2. A1 中输入10个项目
  3. K1 中输入公式=IF(ROW()<512,"0" & DEC2BIN(ROW(),9),"1" & DEC2BIN(ROW()-512,9))
  4. 将第1行复制到第1023行
  5. 将列 K 和PasteSpecialValues复制到 L
  6. 列中
  7. 使用TextToColumns将 L 列解析为 M V
  8. W1 中输入=SUMPRODUCT((A1:J1)*(M1:V1))并复制
  9. W 包含所有可能组合的总和。

    最后,在另一个单元格中输入:

    =COUNTIF(W:W,">=" & 100)
    

    enter image description here

    修改#1:

    要生成 36 位二进制模式,我使用:

    =DEC2BIN(INT(ROW()/2^27),9)&DEC2BIN(INT(MOD(ROW(),2^27)/2^18),9)&DEC2BIN(INT(MOD(ROW(),2^18)/2^9),9)&DEC2BIN(MOD(ROW(),2^9),9)
    

    因此,对于 20 位,只需使用:

    =RIGHT(DEC2BIN(INT(ROW()/2^27),9)&DEC2BIN(INT(MOD(ROW(),2^27)/2^18),9)&DEC2BIN(INT(MOD(ROW(),2^18)/2^9),9)&DEC2BIN(MOD(ROW(),2^9),9),20)
    



    enter image description here

    修改#2:

    要使用VBA执行 TextToColumns 之类的操作,请选择单元格并运行此宏:

    Sub PseudoTextToColumns()
        Dim r As Range, L As Long, i As Long, t As String
        For Each r In Selection
            t = r.Text
            L = Len(t)
            For i = 1 To L
                r.Offset(0, i).Value = Mid(t, i, 1)
            Next i
        Next r
    End Sub
    

    <强> 注:

    这不适用于21件物品。

答案 1 :(得分:1)

VBA强力解决方案

我会分享以下强力解决方案,检查所有可能的组合。它在小型阵列上足够快,最多可达15个条目。它解决了您的问题,您可以将其作为任何粗暴计算的模型,也可以作为优化和应用更快算法的起点。它也可以作为测试您稍后可能实现的任何优化算法的良好基础。

Option Explicit

' Main function. Computes the all combinations and prints those that exceed the target
' Each combination is specified by a mask of bits that specifies whether to take o to leave the entry
Function CombinationsByBruteForce(inputArray() As Double, target As Double) As Long
  Dim mask As Long, count As Long
  For mask = 1 To 2 ^ (1 + UBound(inputArray)) - 1
    If SumByMask(inputArray, mask) > target Then
      count = count + 1
      PrintByMask inputArray, mask
    End If
  Next
  Debug.Print "Total number of successful combinations: " & count
  CombinationsByBruteForce = count
End Function

' computes the sum for a given combination.  The combination is specified by a mask of bits
' that tells which entries belong to the combination (the 1 bits)
Function SumByMask(inputArray() As Double, mask As Long) As Double
  Dim bit As Long
  For bit = 0 To UBound(inputArray)
    If (mask And (2 ^ bit)) <> 0 Then SumByMask = SumByMask + inputArray(bit)
  Next
End Function

' Prints out the entries belonging to a combination specified by a mask
Sub PrintByMask(inputArray() As Double, mask As Long)
  Dim bit As Long
  For bit = 0 To UBound(inputArray)
    If (mask And (2 ^ bit)) <> 0 Then Debug.Print inputArray(bit),
  Next
  Debug.Print
End Sub
' For testing. An array of doubles and a target are specified.
' The variant array is copied into a Double array to improve speed
Sub testing()
  Dim target As Double: target = 350   ' target number to exceed
  Dim test: test = Array(65, 52, 48, 44, 42, 41, 39, 38, 30, 18)

  'convert to explicit array of Double
  ReDim inputArray(UBound(test)) As Double
  Dim i As Long
  For i = LBound(test) To UBound(test): inputArray(i) = test(i): Next

  ' Launsh the brute force computation
  CombinationsByBruteForce inputArray, target
End Sub
上述测试的

输出

 65          52  48          44   42          41  39          38  
 65          52  48          44   42          41  39          30  
 65          52  48          44   42          41  38          30  
 65          52  48          44   42          39  38          30  
 65          52  48          44   41          39  38          30  
 65          52  48          42   41          39  38          30  
 65          52  44          42   41          39  38          30  
 65          52  48          44   42          41  39          38   30         
 65          52  48          44   42          41  39          38   18         
 65          52  48          44   42          41  39          30   18         
 65          52  48          44   42          41  38          30   18         
 65          52  48          44   42          39  38          30   18         
 65          52  48          44   41          39  38          30   18         
 65          52  48          42   41          39  38          30   18         
 65          52  44          42   41          39  38          30   18         
 65          48  44          42   41          39  38          30   18         
 52          48  44          42   41          39  38          30   18         
 65          52  48          44   42          41  39          38   30          18  
Total number of successful combinations: 18

作为使用求解器求解的入口点,您可以尝试BIP模型,其中决策变量是掩码的位。然后,解算器应该应用一些分支和绑定或类似技术来查找组合。但是使用求解器打印出所有成功的组合似乎更难解决,因为它不是优化问题。