|
香川群子 发表于 2014-8-22 11:41
第1行只检查1半、这个是正确的。
但是后面行的禁忌没有道理。除非是连续检查每一行的合并位置是否正确 ...
我说的禁忌搜索不考虑镜像重复的问题,大概是这样子的:- Option Base 1
- Private Const N_NUM% = 8
- Private Type QUEEN
- Selected As Integer
- Available As New Collection
- Disabled As New Collection
- End Type
- Private aQues() As QUEEN
- Private aRes$(), nCnt&
- Sub EightQueens()
- Dim i%, j%, sRep$, k%, t#
- t = Timer
- ReDim aQues(N_NUM)
- For i = 1 To N_NUM
- With aQues(i)
- For j = 1 To N_NUM
- .Available.Add j, CStr(j)
- Next
- End With
- Next
- ReDim aRes(1, 100)
- nCnt = 0
- FindNext 1
- For i = 1 To N_NUM
- With aQues(i)
- Set .Available = Nothing
- Set .Disabled = Nothing
- End With
- Next
- Debug.Print Format(Timer - t, "0.0000") & "s " & nCnt
- Erase aQues
- Erase aRes
- End Sub
- Sub FindNext(ByVal nRow%)
- Dim i%, j%, nCol, sRep$
- On Error Resume Next
- With aQues(nRow)
- For Each nCol In .Available
- .Selected = nCol
- 'sRep = "Row " & nRow & " Select " & nCol & " Removed:"
- For i = nRow + 1 To N_NUM
- aQues(i).Available.Remove CStr(nCol)
- If Err = 0 Then
- .Disabled.Add (i - 1) * N_NUM + nCol
- 'sRep = sRep & "(" & i & "," & nCol & ")"
- Else
- Err.Clear
- End If
- Next
- For j = nCol - 1 To 1 Step -1
- aQues(nRow + nCol - j).Available.Remove CStr(j)
- If Err = 0 Then
- .Disabled.Add (nRow + nCol - j - 1) * N_NUM + j
- 'sRep = sRep & "(" & nRow + nCol - j & "," & j & ")"
- Else
- Err.Clear
- End If
- Next
- For j = nCol + 1 To N_NUM
- aQues(nRow + j - nCol).Available.Remove CStr(j)
- If Err = 0 Then
- .Disabled.Add (nRow + j - nCol - 1) * N_NUM + j
- 'sRep = sRep & "(" & nRow + j - nCol & "," & j & ")"
- Else
- Err.Clear
- End If
- Next
- 'Debug.Print sRep
- If nRow = N_NUM Then
- nCnt = nCnt + 1
- If nCnt > UBound(aRes, 2) Then
- ReDim Preserve aRes(1, UBound(aRes, 2) + 100)
- End If
- For i = 1 To N_NUM
- aRes(1, nCnt) = aRes(1, nCnt) & aQues(i).Selected & ","
- Next
- aRes(1, nCnt) = Left(aRes(1, nCnt), Len(aRes(1, nCnt)) - 1)
- Else
- FindNext nRow + 1
- End If
- 'sRep = "Row " & nRow & " UnSel " & .Selected & " Added Back:"
- For i = 1 To .Disabled.Count
- nCol = (.Disabled(1) - 1) Mod N_NUM + 1
- aQues((.Disabled(1) - 1) \ N_NUM + 1).Available.Add nCol, CStr(nCol)
- 'sRep = sRep & "(" & (.Disabled(1) - 1) \ 8 + 1 & "," & nCol & ")"
- .Disabled.Remove 1
- Next
- 'Debug.Print sRep
- .Selected = 0
- Next
- End With
- End Sub
复制代码 其实是一个树的深度优先的遍历搜索,在每次到达新节点时,需要清理其后节点的可能性,返回时则把原先去掉的可能性加回来。
这段代码速度并不快,但算法是对的,可能用字典取代集合会好些。另外每去掉一个可能性时,可以检查节点的剩余可能,提前返回。 |
|