这道题跟一般的BFS求最短路径不太一样,因为每一个状态是一个矩阵,而不是由一个元素的值或者两个元素的值决定的。所以这道题的做法是将这个2*3的状态转化为字符串。通过定位字符串中‘0’的位置,然后实行上下左右移动的操作。其他的就和普通的BFS模板题一样了。
代码如下:
class Solution {
public:
int slidingPuzzle(vector<vector<int>>& board) {
string destination("123450");//最终的合法状态
unordered_set<string> visited;//用于存放已经访问过的状态
int rowSize = board.size(), colSize = board[0].size();
string source = "";//初始状态
for (int i = 0; i < rowSize; ++i){
for (int j = 0; j < colSize; ++j){
source += char(board[i][j] + '0');
}
}
if (source == destination){
return 0;
}
int minStep = 1;
queue<string> myQue;//广度优先搜索的辅助队列
myQue.push(source);
visited.insert(source);//标记访问
while (!myQue.empty()){
//将此时队列中的所有状态都向下滑动一步,并且将滑动后尾访问过的状态保存早队列的尾端
for (int i = myQue.size(); i > 0; --i){
string front = myQue.front();
myQue.pop();
vector<string> resVec;
move(front, rowSize, colSize, resVec);//滑动front一步,得到所有的滑动状态
//扫描front滑动一步的所有状态
for (auto &str : resVec){
//判断此状态是否访问过
if (visited.find(str) != visited.end()){
continue;
}
if (str == destination){
//第一次出现即为最优解
return minStep;
}
else{
//否则放入队列,并且标记访问
visited.insert(str);
myQue.push(str);
}
}
}
minStep += 1;
}
return -1;
}
//将curr状态已经一次滑动的所有结果放入到resVec中
void move(string &curr, int rowSize, int colSize, vector<string> &resVec){
int zero = curr.find('0');//首先找到零所在的位置
int row = zero / colSize;//确定零所在的行
int col = zero % colSize;//确定零所在的列
//如果零不在首列,则可以进行右滑操作(把零左边的滑块向右滑到零的位置)
if(col > 0){
string tmp = curr;
swap(tmp[zero],tmp[zero-1]);
resVec.push_back(tmp);
}
//如果零不在尾列,则可以进行左滑操作(把零右边的滑块向左滑到零的位置)
if(col < colSize - 1){
string tmp = curr;
swap(tmp[zero],tmp[zero+1]);
resVec.push_back(tmp);
}
//如果零不在首行,则可以进行下滑操作(把零上边的滑块向下滑到零的位置)
if(row > 0){
string tmp = curr;
swap(tmp[zero], tmp[zero - colSize]);
resVec.push_back(tmp);
}
//如果零不在尾行,则可以进行上滑操作(把零下边的滑块向上滑到零的位置)
if(row < rowSize - 1){
string tmp = curr;
swap(tmp[zero], tmp[zero + colSize]);
resVec.push_back(tmp);
}
}
};
参考博客:https://blog.csdn.net/qq_41855420/article/details/90035334