用于迭代表的列中的所有值的算法

时间:2015-08-28 17:40:56

标签: algorithm vba loops iteration brute-force

我正在寻找一种适用于下表的简单算法:

enter image description here

在第一列中,您可以看到约束。算法应该使用第二列来输出迭代,这应该像这样完成:

 0  0  0
 0  0  1
........
 0  0 29
 0  1  0
........
 0  1 29
 0  2  0
 0  2  1
........
........
27  9 29
28  0  0
........
........
28  9 29

目前我有以下代码:

Dim wksSourceSheet As Worksheet
Set wksSourceSheet = Worksheets("Solver")

Dim lngLastRow As Long
Dim lngLastColumn As Long

With wksSourceSheet 
    lngLastRow = IIf(IsEmpty(.Cells(.Rows.Count, 1)), _
        .Cells(.Rows.Count, 1).End(xlUp).Row, .Rows.Count)
    lngLastColumn = IIf(IsEmpty(.Cells(1, .Columns.Count)), _
        .Cells(1, .Columns.Count).End(xlToLeft).Column, .Columns.Count)

    Dim intRowOuter As Integer
    Dim intRowInner As Integer
    For intRowOuter = 2 To lngLastRow
        .Cells(intRowOuter, lngLastColumn).Value = 0
    Next intRowOuter
    For intRowOuter = lngLastRow To 2 Step -1
        For intRowInner = lngLastRow To intRowOuter Step -1
            Dim constraint As Integer
            Dim intConstraintCounter As Integer
            intConstraint = .Cells(intRowInner, 1)
            For intConstraintCounter = 1 To intConstraint 
                .Cells(intRowInner, lngLastColumn).Value = intConstraintCounter
            Next intStampCounter
        Next intRowInner
    Next intRowOuter
End With

这可能是一种正确的方法,但有些不正确。我不幸被困住了,所以我会很感激帮助解决这个问题。

3 个答案:

答案 0 :(得分:1)

解决方案

我建议使用一个数组来存储约束,使用一个来表示计数器。

Dim MaxNum() As Long
Dim myCounter() As Long
ReDim MaxNum(1 To NumDigits)
ReDim myCounter(1 To NumDigits)

接下来,您需要初始化MaxNum。这可能涉及循环包含约束的单元格。类似的东西:

Dim constraintRange As Range
Dim i As integer

Set constraintRange = wksSourceSheet.Range("A2:A4")
For i = 1 to numDigits
    MaxNum(i) = constraintRange.Cells(i,1).Value
Next i

现在我们只需编写增量计数器功能!这个想法非常简单,我们只是从最不重要的数字到最重要的数字。我们递增LSD,如果有溢出,我们将其设置为0,然后将1加到下一个数字。它看起来像这样:

Sub IncrNum(ByRef myNum() As Long, ByRef MaxNum() As Long) 
    Dim i As Integer
    For i = LBound(myNum) To UBound(myNum)
        myNum(i) = myNum(i) + 1
        If myNum(i) > MaxNum(i) Then 'Overflow!
            myNum(i) = 0 'Reset digit to 0 and continue 
        Else
            Exit For 'No overflow so we can just exit
        End If
    Next i
End Sub

这只是一个for-loop!我认为这将是最干净的解决方案:)

注意:要使用此功能,您只需执行IncrNum(myCounter, MaxNum)即可。这会将myCounter的值更改为序列中的下一个值。从这里开始,您可以通过dstRange = myCounter粘贴到范围。

测试

在我自己的测试中,我使用while循环打印出所有值。它看起来像这样:

Do While Not areEqual(MaxNum, myCounter)
    Call IncrNum(myCounter,MaxNum)
    outRange = myCounter
    Set outRange = outRange.Offset(1, 0)
Loop

areEqual只是一个函数,如果参数包含相同的值,则返回true。如果你愿意,我可以提供我的代码,否则我会把它留在外面,以保持我的答案尽可能正常。

答案 1 :(得分:1)

也许可以修改这样的东西以满足您的需求。它使用carry模拟加法:

Sub Clicker(MaxNums As Variant)
    Dim A As Variant
    Dim i As Long, j As Long, m As Long, n As Long
    Dim sum As Long, carry As Long
    Dim product As Long

    m = LBound(MaxNums)
    n = UBound(MaxNums)
    product = 1
    For i = m To n
        product = product * (1 + MaxNums(i))
    Next i
    ReDim A(1 To product, m To n)

    For j = m To n
        A(1, j) = 0
    Next j

    For i = 2 To product
        carry = 1
        For j = n To m Step -1
            sum = A(i - 1, j) + carry
            If sum > MaxNums(j) Then
                A(i, j) = 0
                carry = 1
            Else
                A(i, j) = sum
                carry = 0
            End If
        Next j
    Next i
    Range(Cells(1, 1), Cells(product, n - m + 1)).Value = A
End Sub

用过:

Sub test()
    Clicker Array(3, 2, 2)
End Sub

产生:

enter image description here

答案 2 :(得分:0)

当x除以10时,

x%10x Mod 10给出余数,这样你就得到x的最后一位数。

由于您的问题是专门要求每个数字不超过463857.您可以让计数器从000000递增到463857并且只输出/使用满足以下条件的数字:

IF(x%10 <= 7 AND x%100 <=57 AND x%1000 <= 857 AND x%10000 <=3857 AND x%100000 <= 63857 AND x <= 463857) 
THEN //perform task.