目錄
一.雙向bfs
1.引入
2.概念
3.偽板子及解釋
4.運用hash進行標記
二.引入一道不太難的題目
1.題目
2.解題思路
3.**(如果還不懂,可供參考)
謝謝!廣搜這種東西相信大家都很熟悉吧,相信曾經想剪枝也是快想禿頭了吧。雙向bfs正是一種很好的優化方法。它可以將時間複雜度折半。一般的bfs,如果搜尋樹的深度為l,度為k,則搜尋的最壞時間複雜度為k^l,而如果我們採用雙向bfs,時間複雜度則降為2*(k^(l/2)),自然可以極大的提高搜尋速度。
雙向bfs,顧名思義就是從起始狀態和目標狀態兩面同時開始一起搜,下面有偽板子。
大家一定首先想到了用兩個佇列分別從起始和結束一起搜吧,但是這有點麻煩。我們可以把它優化成乙個佇列,把起始狀態和目標狀態同時存入乙個佇列,就可以依次有序的從兩頭開始搜,只是結構體裡要多定義乙個能判斷是從哪個方向搜過來的的bool變數。
偽板子:
//vis1是正向搜尋的標記,vis2是反向搜尋的標記
while (! queue.empty ())//如果正向和反向搜尋都搜尋到同一狀態,說明找到了最優解
if (vis1[next] == 0)
}else
if (vis2[next] == 0)}}
}
眾所周知,搜尋都是需要標記的,但是下標的定義往往很難。比如說題目給出了乙個矩陣,想要標記每種狀態且不與其他狀態的標記重複就特別難。這時需要運用到雜湊,下面這道題目就是典例。
在乙個5*5的棋盤上有12個白色的騎士和12個黑色的騎士, 且有乙個空位。在任何時候乙個騎士都能按照騎士的走法(它可以走到和它橫座標相差為1,縱座標相差為2或者橫座標相差為2,縱座標相差為1的格仔)移動到空位上。
給定乙個初始的棋盤,怎樣才能經過移動變成如下目標棋盤:
為了體現出騎士精神,他們必須以最少的步數完成任務。
輸入格式
第一行有乙個正整數 ,表示一共有n組資料。
接下來有n個5*5的矩陣,0表示白色騎士,1表示黑色騎士,*表示空位。兩組資料之間沒有空行。
輸出格式
對於每組資料都輸出一行。如果能在15步以內(包括15步)到達目標狀態,則輸出步數,否則輸出 。
樣例輸入
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
樣例輸出
7
-1
資料範圍與提示既然使用雙向bfs,就不難想到把輸入定為起始狀態,目標狀態已經給出。但是這道題目的難點就在於每種狀態的標記。首先我把這個矩陣轉換成整型矩陣,『*』就轉成2。比如就樣例一而言,我就轉換成:
然後在雜湊的時候,我們可以運用最常用的一種辦法:將矩陣轉換成數字。
但是如果直接轉換,就是25位數,這未免也太大了。這是來觀察整個矩陣,會發現最大的數字就是2,所以我們可以把它轉換成三進製數,大大縮小了數字的最大值。那麼最大值:
但是這個如果開陣列的話還是會炸。所以可以想到用map。
直接開乙個:mapvis[2]
vis[0]存從起始狀態開始搜尋的標記,vis[1]存從目標狀態開始搜尋的標記;edge是結構體,有兩個變數:乙個用來標記,另乙個用來存步數。
附雜湊函式:
ll gethash(node a)
}return ans;
}
#include #include #include #include #include using namespace std;
#define ll long long
int t;
struct edge ;
mapvis[2];
int dir[8][2] = , , , , , , , };
int goal[6][6] = ,,,
,,,};struct node st, en;
ll gethash(node a)
}return ans;
}int tow_bfs ()
for (int i = 0; i < 8; i ++)
swap (tmp.word[pos_x][pos_y], tmp.word[tox][toy]);
tmp.x = pos_x, tmp.y = pos_y;}}
}return -1;
}int main ()
}for (int i = 1; i <= 5; i ++)
for (int j = 1; j <= 5; j ++)
en.word[i][j] = goal[i][j];
en.x = en.y = 3;
st.flag = 0;
en.flag = 1;
int ans = tow_bfs ();
if (ans >= 0 && ans <= 15)
printf ("%d\n", ans);
else
printf ("-1\n");
}return 0;
}
SCOI2005 騎士精神
乙個比較直接的思路是bfs爆搜,但這樣只能拿20分,所以考慮優化。在測試樣例時能夠看到深度為7的時候很快就跑出來了,在結合本題最大深度是15,所以可以用雙向bfs來優化,即從兩邊各跑7或8的深度,最後用map合併,有點類似折半搜尋。另外有一些需要注意的小細節已經在 中注釋。code include ...
SCOI2005 騎士精神
輸入格式 第一行有乙個正整數t t 10 表示一共有n組資料。接下來有t個5 5的矩陣,0表示白色騎士,1表示黑色騎士,表示空位。兩組資料之間沒有空行。輸出格式 對於每組資料都輸出一行。如果能在15步以內 包括15步 到達目標狀態,則輸出步數,否則輸出 1。輸入樣例 1 複製2 10110 01 1...
SCOI2005 騎士精神
qwq,ida 演算法太好玩了!在這裡放一波我對迭代加深搜尋 a 演算法的理解 不一定對 迭代加深搜尋就是列舉dfs的最大深度,然後跑dfs,去驗證不超過此深度的前提下是否有解 多用於答案上界很小或是搜尋範圍沒有上界,其實就是防止了dfs一搜到底。a 演算法看起來像是乙個剪枝,定義估價函式,樂觀地估...