對應後面bfs方法的部分
ignatius被魔王抓走了,有一天魔王出差去了,這但是ignatius逃亡的好機會.
魔王住在乙個城堡裡,城堡是乙個a*b*c的立方體,能夠被表示成a個b*c的矩陣,剛開始ignatius被關在(0,0,0)的位置,
離開城堡的門在(a-1,b-1,c-1)的位置,如今知道魔王將在t分鐘後回到城堡,
ignatius每分鐘能從乙個座標走到相鄰的六個座標中的當中乙個.如今給你城堡的地圖,
請你計算出ignatius是否能在魔王回來前離開城堡(僅僅要走到出口就算離開城堡,
假設走到出口的時候魔王剛好回來也算逃亡成功),假設能夠請輸出須要多少分鐘才幹離開,假設不能則輸出-1.
輸入資料的第一行是乙個正整數k,表明測試資料的數量.每組測試資料的第一行是四個正整數a,b,c和t(1<=a,b,c<=50,1<=t<=1000),它們分別代表城堡的大小和魔王回來的時間.然後是a塊輸入資料(先是第0塊,然後是第1塊,第2塊……),每塊輸入資料有b行,每行有c個正整數,代表迷宮的布局,當中0代表路,1代表牆.(假設對輸入描寫敘述不清楚,能夠參考sample input中的迷宮描寫敘述,它表示的就是上圖中的迷宮)
特別注意:本題的測試資料很大,請使用scanf輸入,我不能保證使用cin能不超時.在本oj上請使用visual c++提交.
output
對於每組測試資料,假設ignatius可以在魔王回來前離開城堡,那麼請輸出他最少須要多少分鐘,否則輸出-1.
sample input
3 3 4 20
0 1 1 1
0 0 1 1
0 1 1 1
1 1 1 1
1 0 0 1
0 1 1 1
0 0 0 0
0 1 1 0
0 1 1 0
sample output
分析這個題,本例是乙個三維迷宮,每個點都用三維座標(x,y,z)表示。 主人公每次可以前後左右上下移動,從座標上看就是
(x+1,y,z) (x-1,y,z) (x,y+1,z) (x,y-1,z) (x,y,z+1) (x,y,z-1)
把邊界情況,越界,碰牆剔除
不同於簡單的查詢,結果僅是乙個數或者幾個數。本題的查詢空間為從點(0,0,0,)到點(a-1,b-1,c-1)合法行走路徑
在查詢空間直接拍哪個所有的路徑中尋找一條最短的路徑
與以往的查詢方法相比,在廣度優先搜尋中的查詢方法變的有些特殊,它不在機械地、暴力的遍歷查詢空間中的所有路徑,而採用了某種策略
我們都知道任意乙個位置(x,y,z)走到下乙個位置可擴充套件6個狀態
(x+1,y,z) (x-1,y,z) (x,y+1,z) (x,y-1,z) (x,y,z+1) (x,y,z-1)
將初始節點設為根節點,將每個擴充套件態視為孩子節點,那麼狀態轉移與生成就呈現出了樹的形態
將這棵包含搜尋空間中所有狀態的樹稱為解答樹,採用的搜尋方法實際就是在對這棵解答書進行遍歷時所採用的的方法
bfs就是在遍歷解答樹時使每次狀態轉移時擴充套件出盡可能多的新狀態,按層次遍歷,先有根節點擴充套件出所有深度為1的節點,
再由每乙個深度為1的節點擴充套件出每乙個深度為2的節點,以此類推(且先被擴充套件的節點其深度不大於後擴充套件節點的深度),
深度與行走時間等價。
這樣,當搜尋過程第一次查詢到狀態終點的節點,其記錄的時間即為所需的最短時間。(參照括號的內容理解)
但是,即使這樣查詢結果依舊是非常多,最壞情況下(每個節點都可以擴張),走10步狀態書就會達到6^10,
必須要採取一定的措施來制約狀態的無限擴充套件,這種措施稱之為剪枝。
剪枝顧名思義就是減去解答樹中不可能存在我們需要答案的字數,從而大大減少所需查詢的狀態總數
(重點)
本題中,到達任意乙個中間節點所用的時間都是起點到這個節點的最短時間。在搜尋過程中,若有狀態(x,y,z,t)
其中t不是從起點到達這個節點的最短時間,那麼,我們所需要的答案不可能由該狀態進行若干次擴充套件得到。
等價於在解答樹上,我們所需要查詢的節點的狀態節點必不可能在該狀態節點的子樹上。
根據這個結論,而且bfs中先查找到的狀態深度必不大於查詢後的狀態深度(深度與狀態中的耗時成正比)
所以包含每個立方體中的座標的狀態最多被擴充套件一次。
查詢總數就變成了a*b*c。在可接受範圍內
class node
}public
class 勝利大逃亡 ,,,
,,};public
static
void
main(string args) }}
mark[0][0][0]=true;//標記起點
node start=new node(0, 0, 0, 0);//初始狀態
q.add(start);//將初始態放入佇列
int result=bfs(a,b,c);
system.out.println(result<=t?result:-1);
}public
static
intbfs(int a,int b,int c)
if (maze[nx][ny][nz]==1)
if (mark[nx][ny][nz]==true)
node temp=new node(nx,ny,nz,cur.t+1);//得到新狀態,時間+1
q.add(temp);
mark[nx][ny][nz]=true;//標記該座標
if (nx==a-1&&ny==b-1&&nz==c-1) }}
return -1;//沒找到路}}
與動態規劃題目一樣,廣度優先搜尋的關鍵也是確定狀態
上使用bfs之前要進行剪枝,然後判斷複雜度是否符合要求
廣度優先搜尋的關鍵字
一、狀態。我們確定求解問題中的狀態,通過狀態轉移擴充套件,查詢遍歷所有狀態,從而得到我們需要的答案。
二、狀態擴充套件方式。在bfs中,我們總是盡可能的擴充套件狀態,並將先擴充套件得出的狀態先進行下一次擴充套件。
在解答樹上表現為按層次遍歷所有狀態
三、有效狀態。對於有些狀態我們並不對其進行再一次擴充套件,而是直接捨棄它,因為根據問題分析可知,
目標狀態不會由這些狀態經過若干次擴充套件得到,即目標狀態不可能存在其在解答樹上的子樹上,所以直接捨棄。
(剪枝操作)
四、佇列。為了實現先得出的狀態先進行擴充套件,我們使用佇列,將得到的狀態依次放入隊尾,每次取隊頭元素進行擴充套件。
五、標記、為了判斷哪些位置是有效的,我們要使用標記。
六、有效狀態數。問題中的有效狀態樹與演算法的時間複雜度同數量級,所以在演算法之前必須估算其是否在我們可接受的範圍內
七、最優。bfs常用於解決解決最優值問題,因為其搜尋到的狀態總是按照某個關鍵字遞增(如上題最短時間)
這個特徵非常適合求解最優值的問題,所以問題中一旦出現最少,最短,最優等關鍵字,我們就要考慮用bfs
BFS廣度優先搜尋
廣度優先搜尋,利用佇列實現,結束標誌是隊列為空的時候 承接dfs的演算法實現的講例,對於迷宮問題我們也可以採取廣度優先搜尋實現 include iostream include cstdio include cstdlib using namespace std int map 55 55 int ...
bfs廣度優先搜尋
這一課我們來學習圖的另一種遍歷方法 廣度優先搜尋 breadth first search,簡稱 bfs 這是一種連通圖的常用遍歷策略,通常用於求起點到各點的最短路徑,以及求兩點之間的最優路徑等問題。首先我們先來看看廣度優先搜尋的具體方法吧 對於乙個連通圖,我們假設一開始所有頂點均未被訪問,廣度優先...
BFS廣度優先遍歷
樹的層序遍歷即為bfs的應用。實質就是利用乙個佇列將頂點v的鄰接點儲存,因樹的結構比較特殊,所以不需要進行設定flag訪問位,但圖的情況比較複雜,一般需要對每個結點是否被訪問進行標記。利用bfs可以很容易的利用層數求出最短的步數,比如二叉樹利用層序遍歷求樹的高度,但深搜一般也可以實現。廣度優先搜尋能...