P2324 SCOI2005 騎士精神 題解

2022-02-14 18:25:13 字數 3423 閱讀 2165

csdn同步

原題鏈結

簡要題意:

給定乙個初始棋盤,每次乙個馬可以跳到空位(不考慮蹩腿問題)。求到達目標棋盤的最小步數。

本題其實是 八數碼難題 的乙個強化版,可以去看看 p1379 八數碼難題 題解.

首先本題肯定是搜尋

咦?\(\texttt\) 的效率不是嚴格不優於 \(\texttt\) 的麼?為什麼還要用它呢?

嗯,只要我們加上一點點優化,\(\texttt\) 就不叫 \(\texttt\) 了,它換了乙個名字,叫做 \(\text\) 演算法;如果你再優化億點點,就可以再公升級為 \(\text\) 演算法!

那麼,這些優化是什麼?為什麼只有 \(\texttt\) 才能用呢?而 \(\text\) 都是什麼呢?

我們來一層層解決這個問題。

首先,我們畫出乙個搜尋狀態圖(大概)。

紅色是起點狀態,綠色是目標狀態。在兩紅色輪廓線中的是我們要搜尋的所有狀態。

可是,你會發現有一些東西完全不用搜尋。就比方說,如果跳了一步之後,反而比原來不跳更差了,那麼這步就不用做了

對,這就是乙個有力的剪枝,這樣的搜尋方式被稱為 \(\text\).

那麼,如果確定當前狀態的優劣性呢?

這時我們引進了估價函式 \(h\)的概念。

\(h\) 它的主要作用是估計當前狀態到目標狀態的步數。(與實際答案相差很大,但可作為參考)其特點在於,\(h\)返回的是最小可能的步數,不可能從當前狀態用 \(步完成問題。

所以,如果當前狀態為 \(x\),從起點走了 \(g_x\) 步到達 \(x\),然後其估價函式 咕值函式 為 \(h_x\),\(f_x\) 為起點的估價函式。此時我們力求滿足:

\[f_x = g_x + h_x

\]此時搜尋的效率就取決於 \(h\) 到底怎麼寫。如何快速估計最小步數?(小學數學估算題)

比方說,當前狀態(左)與目標狀態(右)如下:

1 1 1 1 1 -> 0 0 0 0 0

0 1 1 1 1 -> 1 0 0 0 0

0 0 * 1 1 -> 1 1 * 0 0

0 0 0 0 1 -> 1 1 1 1 0

0 0 0 0 0 -> 1 1 1 1 1

我們草率地估計,最少需要 \(24\) 步。為什麼呢?

因為這兩個狀態有 \(24\) 個位置不同(除了空位都不同),那麼如果每一步都能讓乙個位置正確地歸位(即達到目標狀態),這樣也需要 \(24\) 步才能讓每個位置歸位,這是我們能估算的較準確值了。儘管與答案相差較大,但這是我們能估算的最大值了。

那麼,如果當前走了一步之後有 \(25\) 個不同(就比方說你把 \(1,2\) 移到 \(3,3\) 空位上),那麼這種搜尋顯然無效,只會變劣,直接停止。

所以你發現這個圖如果用剪枝的話一步也走不了了(因為無論怎麼走都是 \(25\) 個不同),返回無解。這比你大力 \(\text\) 剪枝要快得多吧!

下面我們引進迭代加深搜尋的概念。

什麼叫做迭代加深呢?

比方說,現在你可能搜尋到的最大深度是 \(10^9\),但答案只有 \(\leq 10\) 步,而寬度隨著深度的增大也**性增長. 此時,你無法用 \(\text\) 和 \(\text\) 任何一種解決。這時需要迭代加深搜尋。什麼意思呢?

大概步驟是:

列舉當前深度(步數),進入 \(\text\).

如果當前搜尋超過深度直接結束;否則向下乙個狀態搜尋。

有解則結束返回當前深度;否則列舉下乙個深度。

深度列舉到一定範圍發現無解則返回無解。

也就是列舉搜尋深度進行搜尋,這樣子一步步搜尋,可以說是基於 \(\text\) 與 \(\text\) 之間的一種演算法吧。

下面我們要將這兩個演算法結合,迭代加深搜尋與 \(\text\) 結合就變成了 \(\text\). 步驟:

列舉最大步數,進入 \(\text\).

如果當前步數 \(+ f\) 值超過最大步數則結束;否則向下乙個狀態搜尋。

有解則結束返回當前步數;否則列舉下乙個步數。

步數列舉到一定範圍發現無解則返回無解。

其實就是在 \(\text\) 基礎上限定深度,在迭代加深搜尋上加乙個有力剪枝。

那麼,本題中這個一定範圍是多少呢?其實你設成 \(15\) 就夠了,因為題目說了:

如果能在 \(15\) 步以內(包括 \(15\) 步)到達目標狀態,則輸出步數,否則輸出 \(-1\)。

如果最大步數超過 \(15\) 就不用再做了。

時間複雜度:\(o(wys)\).(很優卻難以分析的複雜度一般這樣稱呼)

實際得分:\(100pts\).

#pragma gcc optimize(2)

#includeusing namespace std;

inline int read()

int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}

int t,ans=1e9;

char end[6][6]=,

, ,, ,

} ; //結束狀態

char a[6][6];

bool ok=0;

const int dx[8]=;

const int dy[8]=;

inline int g() //不同的個數 , 即估價函式

inline void dfs(int dep,int x,int y,int bs) //如果完全相同則結束搜尋

if(dep==bs) for(int i=0;i<=8;i++)

}int main() if(!g()) //不同的是 0 個 , 即起點與終點相同

for(int bs=1;bs<=15;bs++)

} puts("-1"); fin:;

} return 0;

}

文末:還有一種非常卑鄙的優化,因為如果最後答案是 \(-1\) 時間較大(當然可以通過測試)而其餘答案的耗時較小,採取 「只要程式執行超過某時間就返回 \(-1\) 的方式」,非常不嚴謹但很實用,可以大大提高效率。建議考試不要用,防止極限(如正好 \(15\) 步)資料。

P2324 SCOI2005 騎士精神

ida 演算法 12個白騎士和12個黑騎士在乙個5 5的棋盤上走來走去,求最後走成目標局面的最小步數。看不懂請走傳送門 ida 就是帶有迭代加深和估價函式優化的搜尋。估價函式 對未來搜尋深度的最優估計 通常是達不到的 對於估價函式g,要求g 現實步數 越接近越好,因為越接近能剪的枝就越多 當當前步數...

P2324 SCOI2005 騎士精神

輸入格式 第一行有乙個正整數t t 10 表示一共有n組資料。接下來有t個5 5的矩陣,0表示白色騎士,1表示黑色騎士,表示空位。兩組資料之間沒有空行。輸出格式 對於每組資料都輸出一行。如果能在15步以內 包括15步 到達目標狀態,則輸出步數,否則輸出 1。輸入樣例 1 複製 2 10110 01 ...

洛谷 P2324 SCOI2005 騎士精神

ida 練習題 1 ida iddfs a 1.1 iddfs用於單層 無限 情況但是解層數很少,這時可以限制dfs層數,id為每次的層數限制 1.2 a 具有估價函式,用於bfs快速求解 ida 就是將估價函式用於層數限制的dfs中,如果具有層數的dfs仍然無法滿足時間限制,那麼可以考慮題目性質進...