八数码问题题解
解题思路
算法选择
使用广度优先搜索(BFS)算法,因为:
- BFS按层搜索,保证找到的解决方案是最短路径(最少交换次数)
- 八数码问题的状态空间相对较小(9! = 362880种可能状态)
- BFS能够系统地探索所有可能的状态转移
关键数据结构
struct qj {
vector<vector<char>> arr; // 当前3×3矩阵状态
int dep; // 已走步数(深度)
pair<int, int> place; // 空白格位置
};
状态表示
使用vector<vector<char>>表示3×3矩阵状态,用集合set<vector<vector<char>>>记录已访问状态,避免重复处理。
代码实现详解
1. 初始化与输入处理
vector<vector<char>> math(3, vector<char>(3));
vector<vector<char>> goal(3, vector<char>(3));
set<vector<vector<char>>> vis;
// 定义目标状态
goal[0][0] = '1', goal[0][1] = '2', goal[0][2] = '3';
goal[1][0] = '4', goal[1][1] = '5', goal[1][2] = '6';
goal[2][0] = '7', goal[2][1] = '8', goal[2][2] = 'x';
// 读取输入并记录初始空白格位置
pair<int, int> st;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cin >> math[i][j];
if (math[i][j] == 'x') {
st.x = i;
st.y = j;
}
}
}
2. BFS初始化
queue<qj> q; qj start; start.arr = math; start.dep = 0; start.place = st; q.push(start); vis.insert(math);
3. 方向数组定义
定义四个移动方向(上、下、左、右):
int dx[4] = {0, 0, 1, -1}; // 行方向变化
int dy[4] = {1, -1, 0, 0}; // 列方向变化
4. BFS核心循环
while (!q.empty()) {
auto a = q.front();
q.pop();
vector<vector<char>> now_arr = a.arr;
int depth = a.dep;
auto p = a.place;
// 检查是否达到目标状态
if (now_arr == goal) {
cout << depth << '\n';
return 0;
}
// 尝试四个方向的移动
for (int k = 0; k < 4; k++) {
int nx = p.x + dx[k];
int ny = p.y + dy[k];
// 检查新位置是否合法
if (nx < 0 || nx >= 3 || ny < 0 || ny >= 3) continue;
// 创建新状态并交换
vector<vector<char>> narr = now_arr;
swap(narr[nx][ny], narr[p.x][p.y]);
// 如果新状态未访问过,加入队列
if (vis.find(narr) == vis.end()) {
vis.insert(narr);
qj next;
next.arr = narr;
next.dep = depth + 1;
next.place = {nx, ny};
q.push(next);
}
}
}
算法流程
- 初始化:读取初始状态,记录空白格位置
- BFS准备:将初始状态加入队列和已访问集合
- 状态扩展:对于每个出队状态: 如果是目标状态,返回步数否则尝试四个方向的移动对于每个合法移动,生成新状态如果新状态未访问,加入队列
- 终止条件:找到目标状态或队列为空(无解)
复杂度分析
- 时间复杂度:O(9!) = O(362880),最坏情况下需要遍历所有可能状态
- 空间复杂度:O(9!),需要存储所有已访问状态

京公网安备 11010502036488号