SCOI2005 騎士精神 雙向廣搜

2021-09-21 17:55:21 字數 3252 閱讀 7297

目錄

一.雙向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 演算法看起來像是乙個剪枝,定義估價函式,樂觀地估...