【发布时间】:2018-11-26 01:13:24
【问题描述】:
我的递归不是那么好,我不得不添加一个列表,其中包含所有失败的路径以快速退出其他递归路径,如果它更聪明的话,可能不需要这样做。
无论如何,我要做的是每次检测到重复项时,它要么下降到下一行,要么一直到顶部,并且只有在可能保持值唯一的情况下才尝试填写重复值.然后我得到一堆唯一排序的行。现在我正确编码了所有这些并且它工作得很好..问题是撤消这个以返回相同的解决方案,可能有多个答案我希望能够列出与输入列表长度相同的所有可能答案.
如果比特流包含 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
位为 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
行看起来像这样
(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 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
我通过按 Button2
运行此功能
3个文本框的txtUndoPlaintext.Text = "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"txtUndoBitMask.Text = "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"
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
在index 30 上的0 2 到2 0 与原始文件的检查是关闭的
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
我的问题是我只能得到一个答案,如何才能得到所有答案?
这是我的代码
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
如果您需要这里的值生成器,它是我制作的,我没有问题。 (不能在这个问题中发布,因为它超过了大小限制) https://pastebin.com/raw/0y2DnRhi
【问题讨论】:
-
那里的代码真的太多了。在此处发布问题之前,您确实应该能够进一步缩小问题范围。
-
这是一个影响整个事情的逻辑问题,我不知道在哪里添加另一个循环,所以它会打印出多个解决方案。我想我会继续努力,直到我弄明白为止。
-
您从一个长字符串开始,然后显示另一个据说代表唯一性的长字符串。然后我们发现该初始字符串是通过组合某个表的几行来构建的,以供您的代码处理。然后,您提供了一个代码转储,您希望我们从中推导出逻辑规则,但您承认它不能按您的意愿工作。如果您希望获得建设性反馈,请清楚说明逻辑规则以及示例输入和预期输出。
-
好的抱歉我明天再编辑
-
也许用你所期望的清晰的输入和输出以不同的方式编写它。我很难读到这个:(