关键词:八数码,广度优先搜索BFS
试题链接:
八数码
问题描述:
思路:
用广度优先搜索的方法解决八数码问题。可以构建一颗“状态树”,把九宫格每一种状态视为一个结点,初始状态视为根节点。那么我们计算从初始状态到目标状态的最少步数其实就是相当于求从根节点到目标结点的最少步数,这样就把理解问题尽可以用广度优先算法解决了。
对于广度优先搜索问题首先让根节点入队,对于每个结点有四个搜索方向:然而这四个方向不一定都走得通,还需要考虑到:1.搜索不能超过九宫格边界。2.不能走“回头路”。
对于满足以上条件的结点,我们才可以将它添加进队列之中。
备注:
调试过程中又遇到段错误,我恨段错误。
都是注意力不集中马虎犯的错。
解决方案:
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<string>
#include<cstring>
using namespace std;
//一个结点代表的是一个九宫格的状态
struct NODE {
int x, y; //记录当前0的位置
int step = 0; //记录当前已经走过的步数
char state[3][3]; //记录状态
}node;
NODE s; //根结点,表示初始状态
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
//获取当前状态值
string getState(char m[3][3]) {
string state = "";
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
state += m[i][j];
}
}
return state;
}
bool judge(NODE n) {
if (n.x < 0 || n.x>2 || n.y < 0 || n.y>2) {
return false;
}
else {
return true;
}
}
//计算当前状态的逆序数
bool isAchievable(string s) {
int cnt = 0;
for (int i = 0; i < s.length() - 1; i++) {
for (int j = i + 1; j < s.length(); j++) {
if (s[i] > s[j]&&s[j]!='0') {
cnt++;
}
}
}
if (cnt%2==0) {
return true;
}
return false;
}
int BFS(string target) {
map <string, int> m; //记录不同的结点是否入队
queue<NODE> q;
q.push(s); //第一个结点入队
string str = getState(s.state);
if (str == target)return 0; //输入字符串就是目标字符串,返回步数为0
while (!q.empty()) { //队列不为空,广度优先遍历
NODE next;
NODE n = q.front();
q.pop();
m[str]++;
//遍历搜索上下左右四个方向
for (int i = 0; i < 4; i++) {
//记录0的新位置
next.x = n.x + dx[i];
next.y = n.y + dy[i];
memset(next.state, 0, 9 * sizeof(char));
memcpy(next.state, n.state, 9 * sizeof(char));
//在数组中交换新位置与旧位置的char
if (judge(next)) { //检测是否越界,没有越界就可以走下这一步
swap(next.state[n.x][n.y], next.state[next.x][next.y]);
next.step = n.step + 1;
string s = getState(next.state); //若走下这一步刚好抵达目标状态
if (s == target) {
return next.step;
}
if (m[s] == 0) { //若当前状态没有入队过
q.push(next);
m[s]++;
}
}
}
}
}
int main() {
string target = "123456780";
for (int i = 0; i < 3; i++) {
cin >> s.state[i][0]>> s.state[i][1] >> s.state[i][2];
for (int j = 0; j < 3; j++) {
if (s.state[i][j] == 'x') { //将x换成0,标记初始字符串0的位置
s.state[i][j] = '0';
s.x = i;
s.y = j;
}
}
}
//判断目标是否可达
if (isAchievable(getState(s.state))) {
cout << BFS(target) << endl;
}
else {
cout << -1 << endl;
}
return 0;
}