摘要:[Visual Basic 6.0] 解 陷阱 利用廣度優先搜尋法 (BFS,Breadth-First-Search)
[Visual Basic 6.0] 解 陷阱 利用廣度優先搜尋法 (BFS,Breadth-First-Search)
B.陷阱
Time Limit:1000MS Memory Limit:65536K
Total Submit:78 Accepted:43
Description
身為一個考古學家,勇氣和運氣是不可或缺的成功因素,在古老的國度裡,充斥著現代文明無法理解的謎。有些時候這些謎團讓我們贊嘆先人的成就,但更多機會我們落入古老的詛咒,得費盡心思逃解開謎題,避免成為下一具不知名的枯骨。
考古學家小光在一次埃及歴險的過程中,闖入了一個未曾有人到過的密室,透過牆上的小孔看去,他發現了牆壁後無數的金銀珠寶。正當苦苦思索如何前進的同時,牆壁上一個怪異的突起吸引了他的注意。這個形狀像按鈕的突起恰好位在一個5x5方陣的正中央,旁邊並以古埃及文刻了一串訊息:
XXXXX
XXXXX
XXOXX
XXXXX
XXXXX
「讓二十五位忠心的英靈安息吧!」
好奇心驅使他按下了這個按鈕,沒想到就在這個突起被壓下的同時,周圍的四個按鈕卻浮了起來:
XXXXX
XXOXX
XOXOX
XXOXX
XXXXX
他又按了右上角已被壓下的按鈕,結果三個按鈕一起浮了起來:
XXXOO
XXOXO
XOXOX
XXOXX
XXXXX
經過試驗小光證實了無論按哪一個按鈕,也無論這個按鈕一開始是壓下或是浮上,都將造成按鈕本身和上下左右相鄰按鈕狀態的改變,他有理由相信只要壓下所有按鈕,通往寶藏的秘室之門就會開啟,然而就在此時,兩側的牆壁竟無聲無息地靠了上來,他沒有多少時間了!在他成為陷阱裡的下一個亡魂之前,請你以最快的速度幫助小光讓所有英靈安息吧!
Input
輸入包含數筆測試資料,每筆測試資料均為一由O和X組成的矩陣,至多六行,每行至多六個字元。O表示目前突起的按鈕,X則表示已壓下的,你的目標是將所有按鈕壓下。兩筆測試資料之間以一個空白行分隔,最後一筆資料之後會有一行空白和一個'#'表示結束。
Output
對每一筆測試資料,使用以下格式輸出一行表示完成所需的最小按鈕次數:
Minimum Steps : n
n表示所需最小按鈕次數。如果無論如何無法達成目標,則輸出一行:
Another Skeleton in the Ancient Tomb!
注意:倘若同一按鈕前後被按兩次,應計為兩個按鈕次數。
Sample Input
OO
OO
XOX
OOO
XOX
OX
#
Sample Output
Minimum Steps : 4
Minimum Steps : 1
Another Skeleton in the Ancient Tomb!
# http://218.210.35.237:8080/JudgeOnline/showproblem?problem_id=1046
這一題當我看到題目時想到的就是 廣度優先搜尋法 (BFS,Breadth-First-Search) ,雖然可能有更好的解法,但解最佳解、最佳路徑,就是 BFS 準沒錯!
演算法:
(1) 判斷目前是否已經是答案 ( 是則跳出 )
If InStr(TempNows, "O") = 0 Then
Outs = Outs & "Minimum Steps : " & 步數 & vbCrLf
Exit Sub
End If
(2) 紀錄目前狀態 => 將此次狀態列出所有下一次狀態可能 => 恢復狀態
Sub BFS()
' BFS (每個都按一次)
For I = 1 To X
For J = 1 To Y
GoTemp ' 紀錄
Call Change(I, J) ' 交煥
' 判斷現況是否重複 沒重複繼續
' 現在 = TempNows
TempNows = ""
For I1 = 1 To X
For J1 = 1 To Y
TempNows = TempNows & XY(I1, J1)
Next J1
Next I1
If InStr(TempNows, "O") = 0 Then
Outs = Outs & "Minimum Steps : " & B & vbCrLf
Me.Tag = "Over"
Exit Sub
End If
S = True
For I1 = 0 To K
If ArrayTemp(I1) = TempNows Then S = False
Next I1
If S Then
ArrayTemp(K) = TempNows
K = K + 1
End If
RGoTemp ' 恢復
Next J
Next I
End Sub
Sub Change(I, J)
If I >= 1 And I <= X And J >= 1 And J <= Y Then
If XY(I, J) = "X" Then
XY(I, J) = "O"
Else
XY(I, J) = "X"
End If
' 自己跟周圍相反
Call Change2(I + 1, J)
Call Change2(I - 1, J)
Call Change2(I, J + 1)
Call Change2(I, J - 1)
End If
End Sub
Sub Change2(I, J)
If I >= 1 And I <= X And J >= 1 And J <= Y Then
If XY(I, J) = "X" Then
XY(I, J) = "O"
Else
XY(I, J) = "X"
End If
End If
End Sub
Sub GoTemp() ' 紀錄
For I = 1 To X
For J = 1 To Y
TempXY(I, J) = XY(I, J)
Next J
Next I
End Sub
Sub RGoTemp() ' 恢復
For I = 1 To X
For J = 1 To Y
XY(I, J) = TempXY(I, J)
Next J
Next I
End Sub
Sub RGoTempNow(K) ' 恢復新的
S = 1
For I = 1 To X
For J = 1 To Y
XY(I, J) = Mid(ArrayTemp(K), S, 1)
S = S + 1
Next J
Next I
End Sub
※ 記得要將跑過 BFS 的 狀態設成 某值 ,才不會造成 重複判斷來增加延遲時間。
然後我自己建立的測試資料:
XOOO
XXXO
XXXO
OOOX
OO
OO
XOX
OOO
XOX
OX
OX
XO
XOO
XXX
XOO
OXXX
XOOX
XOXO
XXOO
XOXXX
OXOOX
OXXOO
XOXOX
XXXXX
#
Minimum Steps : 5
Minimum Steps : 4
Minimum Steps : 1
Another Skeleton in the Ancient Tomb !
Minimum Steps : 2
Minimum Steps : 2
Minimum Steps : 3
Minimum Steps : 3
#0xDe 從分享中學習
#Facebook:ProgrammerDe (https://www.facebook.com/MicrosoftDes) 有問題歡迎提問