AcWing 845. 八数码(3阶数字华容道):bfs求最短路,状态表示困难
文章目錄
- 題目
- 題目分析
題目
題目鏈接:AcWing 845. 八數碼(數字華容道)
在一個3×3的網格中,1~8這8個數字和一個“x”恰好不重不漏地分布在這3×3的網格中。
例如:
1 2 3
x 4 6
7 5 8
在游戲過程中,可以把“x”與其上、下、左、右四個方向之一的數字交換(如果存在)。
我們的目的是通過交換,使得網格變為如下排列(稱為正確排列):
1 2 3
4 5 6
7 8 x
例如,示例中圖形就可以通過讓“x”先后與右、下、右三個方向的數字交換成功得到正確排列。
交換過程如下:
1 2 3 \ 1 2 3 \ 1 2 3\ 1 2 3
x 4 6 \ 4 x 6 \4 5 6 \4 5 6
7 5 8 \ 7 5 8 \7 x 8 \7 8 x
現在,給你一個初始網格,請你求出得到正確排列至少需要進行多少次交換。
輸入格式
輸入占一行,將3×3的初始網格描繪出來。
例如,如果初始網格如下所示:
1 2 3
x 4 6
7 5 8
則輸入為:1 2 3 x 4 6 7 5 8
輸出格式
輸出占一行,包含一個整數,表示最少交換次數。
如果不存在解決方案,則輸出”-1”。
輸入樣例:
2 3 4 1 5 x 7 6 8
輸出樣例
19
題目分析
任意的初始狀態start,比如是start=“23415x769”,最終狀態是end=“12345678x” 求初始狀態變成 最終狀態end的最少步數。
這里需要抽象一下,將一個狀態(一個字符串) 抽象成圖中的一個結點a,如果一個狀態可以變成另一個狀態b,就在圖中兩個結點a和b之間建立一條有向邊a→ba\rightarrow ba→b,邊的權值是1.
那么該問題就變成:給定一個起點 和一個終點,從起點到終點最少走多少步。 可以使用BFS()來求最短路。
BFS()需要兩個數據結構:1個隊列queue,一個距離數組dist[ ]
難點如下:
解決方法:
想明白這些表示的問題,真正的難點在于如何實現狀態轉移
start="23415x769"這個狀態可以狀態成幾種狀態?
1) 需要把這個一維字符串轉換成二維的小矩陣
映射方法(假設矩陣每行m個數) 則 一維下標t轉換為二維下標(x,y) 有如下公式:
2)狀態轉移:二維矩陣中的點(x,y)可以轉移到它的上下左右四個方向。
3)最后再將二維矩陣坐標映射成1維字符串中的下標。
二維小矩陣中坐標恢復到一維坐標:
然后就是標準的bfs模板。
請看代碼:
ac代碼
#include<iostream> #include<algorithm> #include<unordered_map> #include<queue>#include<string> using namespace std;int bfs(string start){string end="12345678x";//終點queue<string> q; unordered_map<string,int> d;//距離數組q.push(start);d[start]=0;int dx[4]={0,0,-1,1}, dy[4]={1,-1,0,0};while(q.size()){auto t=q.front();//t為字符串q.pop();int dist=d[t];if(t==end) return dist; //到了終點 返回 dist//狀態轉移int k=t.find('x'); //找到x的位置//一維數組下標轉化為二維數組下標(x,y)int x= k/3,y=k %3; //(x,y)為空格x的位置for(int i=0;i<4;i++){int a= x + dx[i] , b =y +dy[i]; //(a,b)為空格上下左右的某一個值if(a>= 0 && a<3 && b>=0 && b<3 ){swap(t[k],t[a*3+b]); //二維下標對應到一維下標 ,狀態更新if(!d.count(t)){ //之前沒搜到d[t]=dist+1;q.push(t);}swap(t[k],t[a*3+b]); //狀態恢復}}}return -1; //到不了終點 返回-1 }int main(){string start;for(int i=0;i<9;i++){char c;cin>>c;start+= c;}cout<<bfs(start) <<endl;return 0;}總結
以上是生活随笔為你收集整理的AcWing 845. 八数码(3阶数字华容道):bfs求最短路,状态表示困难的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Leetcode199二叉树右视图[C+
- 下一篇: Leetcode5633. 计算力扣银行