八数码
题目描述
思路
八数码问题是bfs中的一类经典问题。
一般的bfs是那种走迷宫的题目,是问你从一个点到另一个点的最短距离或最小操作。
而八数码问题则是问你从初始状态到另一个状态的最小操作,大概的思路与迷宫问题差不
多,但主要有如下几个问题:
- 如何保存每次操作后的状态
- 如何记录每次操作后的步数
- 如何判断当前状态是否与之前的状态重复
1.☀️如何保存每次操作后的状态
将三维矩阵转换为一维的字符串来进行状态保存
1 2 3
X 4 6 -------------------------------------> "123x46758"
7 5 8
2.☀️如何记录每次操作后的步数
使用unordered_map来定义一个d数组储存步数,
unordered_map <string,int> d
每个字符串表示一种状态,每个状态分别对应当时状态的步数
3.☀️如何判断当前状态是否与之前的状态重复
d数组初始化时为0,如果d数组不为0,则代表之前已出现过此状态
注意:要使用一个临时变量distance储存当前节点的步数d
因为在下面改变字符串后,字符串t会变化,这样就无法确定当前状态的上一个状态
int distance = d[t];
✏️AC代码
#include<bits/stdc++.h>
using namespace std;
int dx[4] = {0, 0, -1, 1};
int dy[4] = {1, -1, 0, 0};
int bfs(string start) {
queue<string>q;
unordered_map<string, int>d;
q.push(start);
d[start] = 0;
string end = "12345678x";
while (q.size()) {
string t = q.front();
q.pop();
if (t == end)return d[t];
int distance = d[t];
int k = t.find('x'); //找到可变换节点的坐标
int x = k / 3, y = k % 3;
for (int i = 0; i < 4; i++) {
int a = x + dx[i];
int b = y + dy[i];
if (a >= 0 && a < 3 && b >= 0 && b < 3) {
swap(t[a * 3 + b], t[k]);
//在一维中将符合条件的节点和可变换节点进行位置交换
if (!d.count(t)) { //如果t在d中未出现过
d[t] = distance + 1;
q.push(t);
}
swap(t[a * 3 + b], t[k]);
//字符串恢复到原来,继续遍历下种状态是否可行
}
}
}
return -1;
}
int main() {
string start;
char c;
for (int i = 0; i < 9; i++) {//二维数组转换为一维
cin >> c;
start += c;
}
cout << bfs(start) << endl;
return 0;
}
同类型题目:
卡片换位
题目描述
思路
总体做法跟八数码基本一致,就是要注意读入是不要直接用cin,
cin无法读入空格,可以使用getline()读入整行再放入另一个字符串中。
其次题意是让A,B位置交换,因此还要提前记录A,B原位置坐标用来后面判断结束
AC代码
#include <iostream>
#include <algorithm>
#include <queue>
#include<unordered_map>
using namespace std;
string start, s;
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
int a, b;//A,B位置
int bfs(string s) {
queue<string>q;
unordered_map<string, int>d;
q.push(s);
d[s] = 0; //初始步数
while (q.size()) {
auto t = q.front();
q.pop();
if (t.find('A') == b && t.find('B') == a) return d[t];
int distance = d[t];
int k = t.find(' '); //找到空格位置
int x = k / 3, y = k % 3; //转换为二维坐标
for (int i = 0; i < 4; i++) {
int fx = x + dx[i], fy = y + dy[i];
if (fx >= 0 && fx < 2 && fy >= 0 && fy < 3) {
swap(t[k], t[fx * 3 + fy]);
if (!d.count(t)) { //此状态未出现过
q.push(t);
d[t] = distance + 1;
}
swap(t[k], t[fx * 3 + fy]);
}
}
}
return -1;
}
int main() {
for (int i = 0; i < 2; i ++ ) {//读入两行
string start;
getline(cin, start);
s += start;
}
for (int i = 0; i < 6; i ++ )
if (s[i] == 'A') a = i; //找到A,B位置
else if (s[i] == 'B') b = i;
cout << bfs(s);
return 0;
}