帮助修改递归函数

时间:2010-06-24 08:54:08

标签: asp.net recursion loops combinatorics nested-loops

给定一个画布,让我们说10x10,并给出3个矩形/正方形。

Canvas = 10x10

矩形1 = 2x2 矩形2 = 3x3 矩形3 = 2x4

我已经创建了一个递归函数来循环画布上每个矩形的每个位置,并且它工作正常。 (我已经包含了以下功能,任何人都希望看到它,但我认为没有必要)。

我们可以看到矩形1和2是不可旋转的IE,如果你将它们中的任何一个旋转90度,它们基本上是相同的形状。但矩形3是可旋转的。

如何更改/构造loop / recurisve函数,使其循环每个矩形的每个位置,以及每次可能的旋转?

目的是遍历画布上每个可能的形状拟合。

感谢您的帮助!

Sub recurse(ByVal startPoint As Integer)

    Dim x As Integer
    Dim y As Integer
    Dim validSolution As Boolean = isSolutionValid()
    Dim loopXTo As Integer
    Dim loopYTo As Integer
    Dim solutionRating As Integer

    'If parent nodes create invalid solution, we can skip (375 iterations from 1,600 iterations saving)
    If validSolution = True Then

        If (startPoint = 0) Then
            loopXTo = Math.Floor((canvasCols - squareObjects(startPoint).sqRows()) / 2)    '576 iterations from 1,680 iterations
            loopYTo = Math.Floor((canvasRows - squareObjects(startPoint).sqCols) / 2)       '31,104 iterations from 90,720 iterations
        Else
            loopXTo = canvasCols - squareObjects(startPoint).sqRows
            loopYTo = canvasRows - squareObjects(startPoint).sqCols

        End If

        'Loop all positions on canvas
        For x = 0 To loopXTo
            For y = 0 To loopYTo

                'Set coords of square
                squareObjects(startPoint).setSquareCords(x, y)

                'Phyiscally place it in canvas
                placeSquareOnCanvas(x, y, squareObjects(startPoint).sqRows, squareObjects(startPoint).sqCols)

                'Recursive, get next square
                If (startPoint + 1 < totalSquares) Then
                    recurse(startPoint + 1)
                Else
                    validSolution = isSolutionValid()

                    'Is solution valud
                    If (validSolution = True) Then
                        solutions = solutions + 1
                    End If

                    iterations = iterations + 1

                    'Response.Write("<br /><b>Iteration " & iterations & "</b>")
                    If (validSolution) Then

                        'Rate solution, record if best
                        solutionRating = rateSolution()
                        If solutionRating > bestCellSaving Then
                            bestCellSaving = solutionRating
                            copySolution()
                        End If
                        'Response.Write(" <span style='color:green'> <B>VALID SOLUTION</B></span> (" & rateSolution() & ")")
                    End If
                    'printCanvas(canvas)

                End If

                squareObjects(startPoint).removeSquare(canvas)

            Next
        Next
    End If

End Sub

5 个答案:

答案 0 :(得分:0)

如果画布总是正方形,那么你不需要改变太多。旋转矩形3的结果与未旋转的矩形相同,只是Canvas的原点不同。想象一下,让Rectangle 3不旋转,将画布向另一个方向旋转90度。这意味着您应该能够对相同的结果使用一些数学来得到答案。

答案 1 :(得分:0)

将(x,y)坐标循环放在自己的函数中。然后在WxH的矩形上调用(x,y)坐标循环,然后在旋转的矩形HxW上再次调用它。

或者,您可以在拾取了两个坐标之后,但在进行递归调用之前,将分支放在(x,y)循环内的矩形的两个旋转上。

在这两种情况下,您都需要注意旋转是否会导致矩形超出边界框的高度或宽度。

答案 2 :(得分:0)

你不能简单地扫描形状列表,对于那些矩形(SizeX != SizeY),用{ SizeX = source.SizeY, SizeY = source.SizeX }添加一个克隆的矩形(例如:旋转的矩形)?

这当然意味着要做两次循环(一个用于未旋转的形状列表,一个用于旋转的一个)。

=&GT;做像

这样的事情
squareObjects(startPoint) = squareObjects(startPoint).Rotate();
recurse(startPoint);

答案 3 :(得分:0)

如果在单独的例程中提取循环,则解决方案相对容易出现。

我已经更改了validSolution逻辑以使代码更短 - 现在我们不会在解决方案无效时调用recurse并且我们不需要在recurse()开头检查isSolutionValid()。这些更改使迭代计数更加困难,因此我删除了该代码,但应该可以稍后添加它。

没有最后一个“If”语句的recurse()例程应该与您的代码完全一样。最后一个“If”语句基本上执行旋转矩形的循环。

我不确定如何实现removeSquare(),但可能需要知道方向才能正常工作。

Sub recurse(ByVal startPoint As Integer)
    Dim loopXTo As Integer
    Dim loopYTo As Integer
    If (startPoint = 0) Then
        loopXTo = Math.Floor((canvasCols - squareObjects(startPoint).sqRows) / 2)
        loopYTo = Math.Floor((canvasRows - squareObjects(startPoint).sqCols) / 2)
    Else
        loopXTo = canvasCols - squareObjects(startPoint).sqRows
        loopYTo = canvasRows - squareObjects(startPoint).sqCols
    End If
    fitSqare(loopXTo, loopYTo, False)
    If (squareObjects(startPoint).sqCols <> squareObjects(startPoint).sqRows) Then
        fitSqare(loopYTo, loopXTo, True)
    End If
End Sub

Sub fitSquare(ByVal loopXTo As Integer, ByVal loopYTo As Integer, ByVal rotate As Boolean)
    Dim x As Integer
    Dim y As Integer
    Dim solutionRating As Integer
    Dim validSolution As Boolean

    'Loop all positions on canvas
    For x = 0 To loopXTo
        For y = 0 To loopYTo
            'Set coords of square
            squareObjects(startPoint).setSquareCords(x, y)

            'Phyiscally place it in canvas
            If (rotate) Then
                placeSquareOnCanvas(x, y, squareObjects(startPoint).sqCols, squareObjects(startPoint).sqRows)
            Else
                placeSquareOnCanvas(x, y, squareObjects(startPoint).sqRows, squareObjects(startPoint).sqCols)
            End If

            validSolution = isSolutionValid()
            'Is solution valud
            If (validSolution) Then
                'Recursive, get next square
                If (startPoint + 1 < totalSquares) Then
                    recurse(startPoint + 1)
                Else
                    solutions = solutions + 1
                    'Rate solution, record if best
                    solutionRating = rateSolution()
                    If solutionRating > bestCellSaving Then
                        bestCellSaving = solutionRating
                        copySolution()
                    End If
                End If
            End If
            squareObjects(startPoint).removeSquare(canvas) 'removeSquare may require additional work to handle rotated state
        Next
    Next
End Sub

答案 4 :(得分:0)

坦率地说,我不认为你的实现是最好的 - 但是如果你不想进行大的改动并制作单独的例程,你可以在相同的函数迭代中将矩形的代码放两次。

所以之后:

'Phyiscally place it in canvas placeSquareOnCanvas(x, y, squareObjects(startPoint).sqRows, squareObjects(startPoint).sqCols)

[......]

End If

            squareObjects(startPoint).removeSquare(canvas)

[......]

您可以进行检查

如果正方形是矩形(宽度&lt;&gt;高度) 然后再次复制相同的代码(在Then代码中),在placeSquareOnCanvas()中使用sqCols更改sqRows。

递归将不再是线性的,因为这将为每个矩形制作2个递归分支。也许写两次相同的代码写不是很好,但结果是正确的,代码更改是最小的,基于代码的这个直接解决方案将比尝试其他调整具有更多的性能。