《P1379 八数码难题》
题目描述
在 3×3 的棋盘上,摆有八个棋子,每个棋子上标有 1 至 8 的某一数字。棋盘中留有一个空格,空格用 0 来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为 123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入格式
输入初始状态,一行九个数字,空格用 0 表示。
输出格式
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数。保证测试数据中无特殊无法到达目标状态数据。
输入输出样例
输入 #1复制
283104765
输出 #1复制
4
说明/提示
样例解释
图中标有 0 的是空格。绿色格子是空格所在位置,橙色格子是下一步可以移动到空格的位置。如图所示,用四步可以达到目标状态。
并且可以证明,不存在更优的策略。
代码实现:
#include <iostream>
#include <queue>
#include <map>
#include <string>
#include <algorithm>
using namespace std;
// 四个方向:上、右、下、左
const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1};
// 检查输入字符串是否为合法的9位数字且包含0-8
bool isValidInput(const string& input) {
if (input.length() != 9) return false;
bool digits[9] = {false};
// 替换为传统for循环
for (int i = 0; i < input.length(); i++) {
char c = input[i];
if (c < '0' || c > '8') return false;
int digit = c - '0';
if (digits[digit]) return false; // 重复数字
digits[digit] = true;
}
return true;
}
// 将字符串状态转换为二维数组中的位置
pair<int, int> findZero(const string& state) {
int pos = state.find('0');
return {pos / 3, pos % 3};
}
// BFS求解最小步数
int bfs(string start, string target) {
if (start == target) return 0;
queue<string> q;
map<string, int> dist;
q.push(start);
dist[start] = 0;
while (!q.empty()) {
string current = q.front();
q.pop();
pair<int, int> zeroPos = findZero(current);
int x = zeroPos.first, y = zeroPos.second;
// 尝试四个方向的移动
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
// 检查新位置是否合法
if (nx >= 0 && nx < 3 && ny >= 0 && ny < 3) {
// 计算0的新位置在字符串中的索引
int newZeroIdx = nx * 3 + ny;
int oldZeroIdx = x * 3 + y;
// 生成新状态
string next = current;
swap(next[oldZeroIdx], next[newZeroIdx]);
// 如果新状态未访问过或找到更短路径
if (dist.find(next) == dist.end()) {
dist[next] = dist[current] + 1;
// 检查是否达到目标
if (next == target) return dist[next];
q.push(next);
}
}
}
}
return -1; // 无法到达目标状态(题目保证不会出现)
}
int main() {
string start, target = "123804765";
// 输入验证
do {
// cout << "请输入初始状态(9位数字,空格用0表示): ";
cin >> start;
if (!isValidInput(start)) {
cout << "输入无效,请输入包含0-8的9位不重复数字。" << endl;
}
} while (!isValidInput(start));
int steps = bfs(start, target);
cout << steps <<endl;
return 0;
}