使用嵌套递归算法vb.net显示所有多个解决方案

使用嵌套递归算法vb.net显示所有多个解决方案,vb.net,recursion,Vb.net,Recursion,我的递归不是很好,我必须添加一个包含所有失败路径的列表,以便快速退出其他递归路径,如果它更聪明的话,可能不需要这样做 1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3 无论如何,我要做的是,每次检测到重复时,它要么下降到下一行,要么一直下降到顶部,并且仅在可能保持值唯一的情况下尝试填充重复值。然后我得到了一组行,它们都是唯一排序的。现在我把所有这些都编好了代码,效果很好。。问题是撤销此操作以获得相

我的递归不是很好,我必须添加一个包含所有失败路径的列表,以便快速退出其他递归路径,如果它更聪明的话,可能不需要这样做

1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
无论如何,我要做的是,每次检测到重复时,它要么下降到下一行,要么一直下降到顶部,并且仅在可能保持值唯一的情况下尝试填充重复值。然后我得到了一组行,它们都是唯一排序的。现在我把所有这些都编好了代码,效果很好。。问题是撤销此操作以获得相同的解决方案,可能有多个答案我希望能够列出所有可能的答案,这些答案与输入列表的长度相同

1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
如果比特流包含2个零,并且在解码时无法在行中插入2个唯一值,因为之前已经使用了某个值,那么将跳过整个当前节点,因为它是错误的答案

1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
假设我有这个号码

1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
位为0表示唯一,1表示重复

0 0 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 0 0 1 1 0 0 1 0 0 1 0 0 1 1 1 1 0 0 0 1 
1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
这些排看起来像这样

(Row 0):  1 9 4 2 3 0 
(Row 1):  4 2 1 3 0 
(Row 2):  4 2 1 0 3 
(Row 3):  2 4 3 
(Row 4):  2 4 1 
(Row 5):  2 3 4 0 
(Row 6):  4 2 0 
(Row 7):  4 1 0 2 
(Row 8):  4 6 3 1 
1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3

所有行组合成一个字符串,用于将其传递给程序

1 9 4 2 3 0 4 2 1 3 0 4 2 1 0 3 2 4 3 2 4 1 2 3 4 0 4 2 0 4 1 0 2 4 6 3 1
1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3

我通过按按钮2运行此功能
3个文本框
txtendoplantext.Text=“1 9 4 2 3 0 4 2 2 1 0 3 2 4 3 2 1 2 3 4 0 4 2 0 4 6 3 1”

txtendobitmask.Text=“0 0 0 0 1 0 1 0 0 1 0 0 0 1 0 1 0 0 1 0 1 0 1 1 0 0 1”

txtOutput(这是一个多行输出),答案打印出来。

1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
我得到的答案是

1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
在其
0 2
2 0
打开
索引30

1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 0 2 4 6 3 1 3
1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
我的问题是我只能得到一个答案如何才能得到所有答案?

1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
这是我的代码

Public bitmask() As Byte
Public FailedPaths As New List(Of String)
Public Uniques()() As Byte

Public Function GetUniquesAt(uniques()() As Byte, CurrentRow As UInteger, ProcessedBits()() As Byte) As Byte()
    Dim eachUniqueIndex As Integer = 0

    Dim UniquesUsed() As Byte
    'ReDim UniquesUsed(0)

    For eachUniqueIndex = 0 To UBound(uniques(CurrentRow), 1)
        If ProcessedBits(CurrentRow)(eachUniqueIndex) = 1 Then
            'Add a new number to this row
            If UniquesUsed Is Nothing Then
                ReDim Preserve UniquesUsed(0)
            Else
                ReDim Preserve UniquesUsed(UniquesUsed.Length)
            End If
            Dim LastValueInRow As Integer = UniquesUsed.Length
            UniquesUsed(LastValueInRow - 1) = uniques(CurrentRow)(eachUniqueIndex)
        End If
    Next

    Return UniquesUsed
End Function

Public Function GetCurrentOffsetForRow(uniques()() As Byte, CurrentRow As UInteger, ProcessedBits()() As Byte) As UInteger
    Dim eachUniqueIndex As Integer = 0

    For eachUniqueIndex = 0 To UBound(uniques(CurrentRow), 1)
        If ProcessedBits(CurrentRow)(eachUniqueIndex) = 0 Then
            Return eachUniqueIndex
        End If
    Next
    Return eachUniqueIndex
End Function

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    txtUndoPlaintext.Text = Replace(txtUndoPlaintext.Text, "  ", " ")
    txtUndoPlaintext.Text = txtUndoPlaintext.Text.TrimStart(CChar(" "))
    txtUndoPlaintext.Text = txtUndoPlaintext.Text.TrimEnd(CChar(" "))

    Dim UniqueList() As Byte = Split(txtUndoPlaintext.Text, " ").[Select](Function(n) Byte.Parse(n)).ToArray()

    txtUndoBitMask.Text = Replace(txtUndoBitMask.Text, "  ", " ")
    txtUndoBitMask.Text = txtUndoBitMask.Text.TrimStart(CChar(" "))
    txtUndoBitMask.Text = txtUndoBitMask.Text.TrimEnd(CChar(" "))

    bitmask = Split(txtUndoBitMask.Text, " ").[Select](Function(n) Byte.Parse(n)).ToArray()

    'Clear uniques from previous runs.
    Uniques = Nothing
    Dim PreviousRow As UInteger = 0

    'Check if unique exists from first row to current row
    Dim CurrentRow As UInteger = 0
    Dim ContainsValueInRow As Boolean = False

    'if uniques current row isn't initialized then initialize it.
    If Uniques Is Nothing Then
        ReDim Uniques(CurrentRow)
        Uniques(CurrentRow) = New Byte() {}
    End If

    Dim ProcessedBits()() As Byte
    ReDim ProcessedBits(CurrentRow)
    ProcessedBits(CurrentRow) = New Byte() {}

    'Load uniques up in the Uniques List
    For Each Value In UniqueList
        ContainsValueInRow = False
        'Check row if it contains the current Value if it does change to next row.
        For eachUniqueIndex = 0 To UBound(Uniques(CurrentRow), 1)
            If Uniques(CurrentRow)(eachUniqueIndex) = Value Then
                ContainsValueInRow = True
                Exit For
            End If
        Next

        If ContainsValueInRow Then
            CurrentRow += 1
            ReDim Preserve Uniques(CurrentRow)
            Uniques(CurrentRow) = New Byte() {}

            ReDim Preserve ProcessedBits(CurrentRow)
            ProcessedBits(CurrentRow) = New Byte() {}
        End If

        Dim LastValueInRow As Integer = Uniques(CurrentRow).Length
        'Add new number to this row
        ReDim Preserve Uniques(CurrentRow)(LastValueInRow)
        Uniques(CurrentRow)(LastValueInRow) = Value

        ReDim Preserve ProcessedBits(CurrentRow)(LastValueInRow)
        ProcessedBits(CurrentRow)(LastValueInRow) = 0
    Next

    FailedPaths.Clear()

    CurrentRow = 0

    Dim CurrentProcessedByte As Long = 0
    Dim CurrentOffset As Long = 0
    Dim FinalString As String = ""

    Dim ExitedTooSoon As Boolean = False

    ProcessTreeNodes(FinalString, ProcessedBits, CurrentProcessedByte, PreviousRow, CurrentRow)

    Dim output As String
    output = output & "Final Decoded Answer: " & FinalString & vbCrLf
    output = output & "Stopped at row: " & CurrentRow & vbCrLf

    txtOutput.Text = txtOutput.Text & output
End Sub

Public Sub ProcessTreeNodes(_FinalString As String, _ProcessedBits()() As Byte, CurrentProcessedByte As Byte, PreviousRow As UInteger, CurrentRow As UInteger)

    'Clone Data to get rid of References, so we always copy here
    Dim ProcessedBits(_ProcessedBits.GetUpperBound(0))() As Byte
    For i = 0 To _ProcessedBits.Length - 1
        ProcessedBits(i) = _ProcessedBits(i).Clone()
    Next

    Dim FinalString As String = _FinalString.Clone()
    Dim LoopTwo As Boolean = False
    Dim ExitedTooSoon As Boolean = False
    Dim CurrentOffset As UInteger = GetCurrentOffsetForRow(Uniques, CurrentRow, ProcessedBits)

    While True
        'If finished with everything just simply exit this loop
        If bitmask.Length = CurrentProcessedByte Then Exit While

        'Unique currently on this row no need any extra processing
        If bitmask(CurrentProcessedByte) = 0 Then

            'Bad Sub Node.. exit it
            If Uniques(CurrentRow).Length = CurrentOffset Then
                ExitedTooSoon = True
                Exit While
            End If

            FinalString = FinalString & " " & Uniques(CurrentRow)(CurrentOffset)
            'Mark as processed for future calculations
            ProcessedBits(CurrentRow)(CurrentOffset) = 1
        End If

        'Switch to a new row
        If bitmask(CurrentProcessedByte) = 1 Then
            CurrentOffset = 0
            PreviousRow = CurrentRow
            'If Blank Row -> Build a next Row Or Start from Top.
            'If the row is Row 0, then next row is Row 1, but if Row 1.. then next row to check is Row 0 etc..

            If CurrentRow = 0 Then
                CurrentRow = 1
            ElseIf CurrentRow > 0 Then
                CurrentRow = 0
            End If

            Dim MainRowUniquesUsed() As Byte
            Dim CurrentRowUniques() As Byte

            'Do crazy loop checks to see whats the next value.
            While True
                If FailedPaths.Contains(FinalString) Then
                    ExitedTooSoon = True
                    Exit While
                End If

                MainRowUniquesUsed = GetUniquesAt(Uniques, PreviousRow, ProcessedBits)
                CurrentRowUniques = GetUniquesAt(Uniques, CurrentRow, ProcessedBits)
                CurrentOffset = GetCurrentOffsetForRow(Uniques, CurrentRow, ProcessedBits)

                If LoopTwo Then
                    'Get a list of all Rows used +1
                    Dim listsOfUniquesUsed As New List(Of Byte())
                    Dim LastRow As Long = 0
                    Dim IsPossible As Boolean = True
                    For row As Long = 0 To ProcessedBits.Length - 1
                        'Get a list of every value used in every row

                        'Don't process the tree until at least 2 rows are used.. then it will use the 3rd row if possible
                        If ProcessedBits.Length > 1 AndAlso ProcessedBits(1)(0) = 0 Then
                            Exit For
                        End If
                        If ProcessedBits(row)(0) = 1 Then
                            listsOfUniquesUsed.Add(GetUniquesAt(Uniques, row, ProcessedBits))
                            'Get the first value of a un-used Row just to checking if it's a possible answer too.
                        ElseIf ProcessedBits(row)(0) = 0 Then
                            listsOfUniquesUsed.Add(New Byte() {Uniques(row)(0)})
                            LastRow = row
                            Exit For
                        End If
                        'Hit last row and last row is already used so this whole thing is not possible
                        If row = ProcessedBits.Length - 1 AndAlso ProcessedBits(row)(0) = 1 Then
                            IsPossible = False
                        End If
                    Next

                    If IsPossible Then
                        'This checks to make sure all the commons that are partially in all lists.
                        Dim list() As Byte = listsOfUniquesUsed.SelectMany(Function(x) x).Distinct().Where(Function(item) listsOfUniquesUsed.All(Function(l) l.Contains(item))).ToArray()

                        'If a possible match is found 
                        'make sure there Is a row below the current row, If no point in doing it.
                        'If list.Count > 0 AndAlso PreviousRow + 1 < Uniques.Length AndAlso FailedPaths.Where(Function(c) c.StartsWith(FinalString)).Count = 0 Then
                        If list.Count > 0 AndAlso PreviousRow + 1 < Uniques.Length AndAlso Not FailedPaths.Contains(FinalString) Then
                            'CurrentOffset Spoofed
                            Dim PreviousRowSpoofed As UInteger = CurrentRow
                            Dim CurrentRowSpoofed As UInteger = LastRow

                            'Possible 2 answers are possible!
                            ProcessTreeNodes(FinalString, ProcessedBits, CurrentProcessedByte, PreviousRowSpoofed, CurrentRowSpoofed)
                        End If
                    End If
                End If

                'Quick fix
                If MainRowUniquesUsed Is Nothing Then
                    CurrentRow = PreviousRow
                    CurrentOffset = GetCurrentOffsetForRow(Uniques, CurrentRow, ProcessedBits)
                    FinalString = FinalString & " " & Uniques(CurrentRow)(CurrentOffset)
                    'Mark as processed for future calculations
                    ProcessedBits(CurrentRow)(CurrentOffset) = 1
                    LoopTwo = True
                    Exit While
                End If

                'Next Row is blank, then its just a fresh entry
                If CurrentRowUniques Is Nothing Then
                    FinalString = FinalString & " " & Uniques(CurrentRow)(CurrentOffset)
                    'Mark as processed for future calculations
                    ProcessedBits(CurrentRow)(CurrentOffset) = 1
                    LoopTwo = True
                    Exit While
                    'Scan this row if its a possible insert here or possible go to next
                ElseIf CurrentRowUniques IsNot Nothing Then
                    Dim ValueNotUsed() As Byte = Uniques(CurrentRow) _
                    .Select(Function(item, index) New With {.Item = item, .Index = index}) _
                    .Where(Function(x) ProcessedBits(CurrentRow)(x.Index) = 0) _
                    .Select(Function(x) x.Item).ToArray()

                    'If no values are possible, then go check next row.
                    If ValueNotUsed.Length = 0 Then
                        'If the Next Row is the Row we were in, just before this one Jump 2 rows
                        If CurrentRow + 1 = PreviousRow Then
                            CurrentRow = CurrentRow + 2
                        Else
                            CurrentRow = CurrentRow + 1
                        End If
                        'This quick fix isn't checked could be wrong
                        'it just starts from the top if it hit a row past the last row.
                        If CurrentRow >= Uniques.Length Then
                            CurrentRow = 0
                        End If
                        Continue While
                        'This is a possible answer area (where it would spawn multiple nodes to keep recursively finishing it.)
                    ElseIf ValueNotUsed.Length > 0 Then
                        If Not MainRowUniquesUsed.Contains(ValueNotUsed(0)) Then
                            'The next pattern isn't found in this Row, so we hope next row.
                            'Keep hopping rows until we hit the row which is the farthest one
                            'Then we could exit out.
                            'If the Next Row is the Row we were in, just before this one Jump 2 rows

                            If CurrentRow + 1 = PreviousRow Then
                                CurrentRow = CurrentRow + 2
                            Else
                                CurrentRow = CurrentRow + 1
                            End If

                            If CurrentRow + 1 > PreviousRow Then
                                'Hit the row we currently on and still no match so its a bad loop
                                ExitedTooSoon = True
                                Exit While
                            ElseIf CurrentRow >= Uniques.Length Then
                                'Probably does not work?
                                CurrentRow = 0
                            End If
                            Continue While
                        End If
                        'Scan Previous Rows for the same answer as in this Row.
                        FinalString = FinalString & " " & Uniques(CurrentRow)(CurrentOffset)
                        'Mark as processed for future calculations
                        ProcessedBits(CurrentRow)(CurrentOffset) = 1
                        LoopTwo = True
                        Exit While
                    End If
                End If
            End While
        End If

        If ExitedTooSoon Then
            Exit While
        End If

        CurrentOffset += 1
        CurrentProcessedByte += 1
    End While

    If ExitedTooSoon Then
        FailedPaths.Add(FinalString)
        Exit Sub
    End If

    Dim output As String
    output = output & "TreeNode Decoded Answer: " & FinalString & vbCrLf
    output = output & "Stopped at row: " & CurrentRow & vbCrLf

    txtOutput.Text = txtOutput.Text & output
End Sub
1 9 4 2 4 2 4 2 1 2 4 3 2 4 1 2 3 4 0 3 1 3 0 4 2 0 4 1 0 0 2 0 4 6 3 1 3
公共位掩码()作为字节
公共失败路径作为新列表(字符串)
公共Uniques()()作为字节
公共函数GetUniquesAt(uniques()()作为字节,CurrentRow作为UInteger,ProcessedBits()()作为字节)作为字节()
Dim eachUniqueIndex为整数=0
Dim UniquesUsed()作为字节
'ReDim UniquesUsed(0)
对于每个队列索引=0到UBound(uniques(CurrentRow),1)
如果处理位(CurrentRow)(每个chuniqueIndex)=1,则
'向此行添加新编号
如果UniquesUsed不算什么
使用的ReDim保留唯一性(0)
其他的
ReDim保存唯一使用的(唯一使用的长度)
如果结束
Dim LastValueInRow作为整数=唯一使用的长度
使用的唯一性(LastValueInRow-1)=唯一性(CurrentRow)(每种唯一性索引)
如果结束
下一个
返回唯一使用的
端函数
公共函数GetCurrentOffsetForRow(uniques()()作为字节,CurrentRow作为UInteger,ProcessedBits()()作为字节)作为UInteger
Dim eachUniqueIndex为整数=0
对于每个队列索引=0到UBound(uniques(CurrentRow),1)
如果处理的位(CurrentRow)(每个chuniqueIndex)=0,则
返回每个队列索引
如果结束
下一个
返回每个队列索引
端函数
私有子按钮2\u单击(发送者作为对象,e作为事件参数)处理按钮2。单击
txtendoplantext.Text=替换(txtendoplantext.Text,“,”)
txtendoplantext.Text=txtendoplantext.Text.TrimStart(CChar(“”)
txtendoplantext.Text=txtendoplantext.Text.TrimEnd(CChar(“”)
Dim UniqueList()的形式为Byte=Split(txtendoplantext.Text,“”。[选择](函数(n)Byte.Parse(n)).ToArray()
txtendobitmask.Text=替换(txtendobitmask.Text,“,”)
txtendobitmask.Text=txtendobitmask.Text.TrimStart(CChar(“”)
txtendobitmask.Text=txtendobitmask.Text.TrimEnd(CChar(“”)
bitmask=Split(txtendobitmask.Text,“”。[选择](函数(n)Byte.Parse(n)).ToArray()
'从以前的运行中清除Unique。
唯一=无
将上一行变暗为UInteger=0
'检查从第一行到当前行是否存在唯一性
尺寸CurrentRow为UInteger=0
Dim包含的VALUESINROW为布尔值=False
'如果当前行未初始化,则初始化它。
如果Uniques不算什么
ReDim Uniques(当前行)
Uniques(CurrentRow)=新字节(){}
如果结束
将ProcessedBits()变为字节
ReDim处理位(当前行)
ProcessedBits(CurrentRow)=新字节(){}
'将uniques加载到uniques列表中
对于唯一列表中的每个值
ContainsValueInRow=False
'检查行是否包含当前值,如果它确实更改为下一行。
对于每个队列索引=0到UBound(Uniques(CurrentRow),1)
如果Uniques(CurrentRow)(eachUniqueIndex)=值,则
ContainsValueInRow=True
退出
如果结束
下一个
如果包含以下值,则
CurrentRow+=1
ReDim保留唯一性(当前行)
Uniques(CurrentRow)=新字节(){}
ReDim保留已处理位(当前行)
ProcessedBits(CurrentRow)=新字节(){}
如果结束
Dim LastValueInRow As Integer=Uniques(当前行)。长度
'将新编号添加到此行
ReDim保留唯一性(当前行)(LastValueInRow)
Uniques(CurrentRow)(LastValueInRow)=值
ReDim保留已处理位(当前行)(LastValueInRow)
已处理位(当前行)(LastValueInRow)=0
下一个
FailedPaths.Clear()
CurrentRow=0
Dim CurrentProcessedByte的长度=0
长=0时的Dim CurrentOffset
Dim FinalString As String=“”
布尔值为False时立即退出Dim
ProcessTreeNodes(最后一个字符串、ProcessedBits、CurrentProcessedByte、PreviousRow、CurrentRow)
将输出设置为字符串
输出=输出和“最终解码答案:”&FinalString&vbCrLf
输出=输出和“在以下行停止:”&CurrentRow&vbCrLf
txtOutput.Text=txtOutput.Text&output
端接头
公共子进程树节点(_FinalString作为字符串,_ProcessedBits()()作为字节,CurrentProcessedByte作为字节,前一行A