我也想说,我不在乎算法生成的哪种解决方案,因为我知道对于相同数量的移动有很多解决方案。
我只想要当前谜题的最少移动的任何解决方案。
谢谢你。我实在想不出有什么模式,我只知道最小的数字必须放在前面,最大的数字必须放在后面,但诀窍是它一次移动两个数字,一个从前面,一个从后面,就像一起使用更可修改的堆栈进行排序一样。
这个游戏只有2种移动..
- 在任何偏移量处进行左循环旋转(除了最后一个字节)右
- 在任何偏移量处进行循环旋转(除了最后一个字节)
这是该功能的代码
Public Function CyclicRotationOffset(ByVal data() As Byte, ByVal beginOffset As Integer, ByVal leftDirection As Boolean) As Byte() 'Left Direction = true '-------------------------------------------------------- 'Shifted cyclically rotation If [a, b, c] then [b, c, a] '-------------------------------------------------------- 'Left Direction = false '-------------------------------------------------------- 'Shifted cyclically rotation If [a, b, c] then [c, a, b] '-------------------------------------------------------- If beginOffset = UBound(data) Then 'last byte cannot do anything. Return data End If Dim newdata() As Byte ReDim newdata(UBound(data)) If leftDirection = True Then newdata(UBound(newdata)) = data(beginOffset) '1st element will be last. For i = beginOffset To UBound(data) - 1 newdata(i) = data(i + 1) Next i Else newdata(beginOffset) = data(UBound(data)) 'last element will be first. For i = beginOffset + 1 To UBound(data) newdata(i) = data(i - 1) Next i End If If beginOffset > 0 Then Buffer.BlockCopy(data, 0, newdata, 0, beginOffset) End If Return newdataEnd Function
这里有两个例子
———————————————-
数据,在6次移动中解决(使用蛮力和函数)。
2, 7, 3, 1, 6, 4, 5, 8, 9
———————————————-
蛮力旋转
3次左,3次右
———————————————-
1, 左
2, 左
0, 右
6, 右
3, 左
5, 右
———————————————
2, 3, 1, 6, 4, 5, 8, 9, 7
2, 3, 6, 4, 5, 8, 9, 7, 1
1, 2, 3, 6, 4, 5, 8, 9, 7
1, 2, 3, 6, 4, 5, 7, 8, 9
1, 2, 3, 4, 5, 7, 8, 9, 6
1, 2, 3, 4, 5, 6, 7, 8, 9 <- 最终一个产生排序答案
———————————————-
这里是一个更难的例子(这个难倒了我)
在7次移动中解决(使用蛮力)
数据=
3, 9, 7, 4, 2, 5, 1, 6, 8
答案=
1, 2, 3, 4, 5, 6, 7, 8, 9
4次左,3次右
移动步骤
6, 左
0, 右
3, 左
7, 右
2, 左
3, 左
1, 右
3, 9, 7, 4, 2, 5, 6, 8, 1
1, 3, 9, 7, 4, 2, 5, 6, 8
1, 3, 9, 4, 2, 5, 6, 8, 7
1, 3, 9, 4, 2, 5, 6, 7, 8
1, 3, 4, 2, 5, 6, 7, 8, 9
1, 3, 4, 5, 6, 7, 8, 9, 2
1, 2, 3, 4, 5, 6, 7, 8, 9
这是我找到第一个谜题6次移动解决方案的代码,但对于第二个谜题,它处理得不对,所以解决方案需要14次移动而不是最优的7次移动。
Public Structure OffsetMove Dim moveId As Byte Dim randomOffset As Byte Public Sub New(ByVal moveId As Byte, ByVal randomOffset As Byte) Me.moveId = moveId Me.randomOffset = randomOffset End SubEnd StructurePublic Function SortDataCyclic(ByVal data() As Byte) As List(Of OffsetMove) Dim answer() As Byte ReDim answer(UBound(data)) Buffer.BlockCopy(data, 0, answer, 0, data.Length) Array.Sort(answer) Dim newdata() As Byte ReDim newdata(UBound(data)) Buffer.BlockCopy(data, 0, newdata, 0, data.Length) Dim i As Long = 0 Dim j As Long = 0 Dim k As Long = 0 Dim l As Long = 0 Dim solutionCount As Integer = 0 Dim movesTaken As New List(Of OffsetMove) Debug.Print("---------------------------------------------") Dim sortedPairs As New List(Of Byte) While j < 8 If sortedPairs.Count >= 3 Then 'Insertion right cyclic rotations go here While l < 9 k = 0 While k < 9 If newdata(k) > newdata(8) Then Exit While k += 1 End While If k = 9 Then 'fully sorted already, nothing left to insert. Exit While End If newdata = CyclicRotationOffset(newdata, k, False) movesTaken.Add(New OffsetMove(1, k)) printDebug(newdata) l += 1 End While 'Exit the while, everything is sorted. Exit While '1, 2, x, x, x, x ElseIf j + 1 < 9 AndAlso _ newdata(j + 1) = (newdata(j) + 1) Then sortedPairs.Add(j) j += 2 '1, x, 2, x, x, x ElseIf j + 2 < 9 AndAlso _ newdata(j + 2) = (newdata(j) + 1) Then newdata = CyclicRotationOffset(newdata, (j + 1), True) movesTaken.Add(New OffsetMove(0, (j + 1))) printDebug(newdata) j = 0 'No pair pattern at all. Else newdata = CyclicRotationOffset(newdata, j, True) movesTaken.Add(New OffsetMove(0, j)) printDebug(newdata) End If End While Return movesTakenEnd FunctionPublic Sub printDebug(ByVal data() As Byte) Debug.Print(data(0) & ", " & data(1) & ", " & data(2) & ", " & data(3) & ", " & data(4) & ", " & data(5) & ", " & data(6) & ", " & data(7) & ", " & data(8))End Sub
回答:
我使用了你的代码,得到了与你不同的结果集。我认为部分原因在于你在while循环中对sortedPairs.Count的逻辑处理。我也对i、j、k和l之间的区别感到困惑。所以我使用了一些稍微不同的逻辑重写了你的While循环。
Dim currentNumber As Integer = 1 Dim currentPositionOfNumber As Integer = 0 While currentNumber - 1 < 8 currentPositionOfNumber = GetIndexOfNumber(newdata, currentNumber) If currentNumber - 1 = currentPositionOfNumber Then 'do nothing ElseIf currentNumber = currentPositionOfNumber Then '如果需要移动的数字在它需要的位置的直接右侧,那么只需向左旋转一次 newdata = CyclicRotationOffset(newdata, currentNumber - 1, True) movesTaken.Add(New OffsetMove(1, k)) printDebug(newdata) ElseIf currentPositionOfNumber = 8 Then '如果需要移动的数字在最后一个位置,则旋转到正确的位置 newdata = CyclicRotationOffset(newdata, currentNumber - 1, False) movesTaken.Add(New OffsetMove(1, k)) printDebug(newdata) ElseIf currentNumber = newdata(currentPositionOfNumber + 1) - 1 Then '如果数字不在上述任何位置,但它右侧的数字是下一个更高的数字,那么只需向左旋转直到这对数字在正确的位置 Do Until GetIndexOfNumber(newdata, currentNumber) = currentNumber - 1 newdata = CyclicRotationOffset(newdata, currentNumber - 1, True) movesTaken.Add(New OffsetMove(1, k)) printDebug(newdata) Loop Else '向左旋转一次,然后向右旋转到正确的位置 newdata = CyclicRotationOffset(newdata, currentPositionOfNumber, True) movesTaken.Add(New OffsetMove(1, k)) printDebug(newdata) newdata = CyclicRotationOffset(newdata, currentNumber - 1, False) movesTaken.Add(New OffsetMove(1, k)) printDebug(newdata) End If currentNumber += 1 End While
我还有一个函数来查找当前正在评估的数字在数组中的位置
Public Function GetIndexOfNumber(data() As Byte, number As Integer) As Integer For i = 0 To 8 If data(i) = number Then Return i NextEnd Function
有了这个,我得到了以下结果…测试1 = 6次移动测试2 = 7次移动