在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局,找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
八数码问题是典型的bfs问题,bfs问题经常用来解决最短路径问题。
输入案例;:
1 2 3 0 8 4 7 6
1 0 3 2 4 7 6 5
输出样例:
2
#include<iostream>
#include<queue>
using namespace std;
int dir[4][2] = { {-1,0},{0,-1},{1,0},{0,1} };
const int len = 362880;
int start[9];
int goal[9];
struct node
{
int state[9];
int dis;
};
int visited[len] = { 0 };//判重数组
long int factory[] = { 1,1,2,6,24,120,720,5040,40320,362880 };
//判重函数,康托展开。
bool Cantor(int str[], int n) {
long result = 0;
for (int i = 0; i < n; i++) {
int count = 0;
for (int j = i + 1; j < n; j++) {
if (str[i] > str[j]) {
count++;
}
}
result += count * factory[n - 1 - i];
}
if (!visited[result]) {
visited[result] = 1;
return 1;
}
else
return 0;
}
int bfs() {
node head;
memcpy(head.state, start, sizeof(head.state));
head.dis = 0;
Cantor(head.state, 9);
queue<node> q;
q.push(head);
while (!q.empty()) {
head= q.front();
if (memcmp(head.state, goal, sizeof(goal)) == 0) {
return head.dis;
}
q.pop();
int z;
//找到此时的0的位置
for (z = 0; z < 9; z++) {
if (head.state[z] == 0)
break;
}
//转化为二维坐标
int x = z % 3;
int y = z / 3;
for (int i = 0; i < 4; i++) {
int dx = x + dir[i][0];
int dy = y + dir[0][i];
int nz = 3 * dy + dx;
if (dx >= 0 && dx < 3 && dy >= 0 && dy < 3) {
node n1;
memcpy(&n1, &head, sizeof(node));
swap(n1.state[z], n1.state[nz]);
n1.dis++;
if (Cantor(n1.state, 9)) {
q.push(n1);
}
}
}
}
return -1;
}
int main() {
for (int i = 0; i < 9; i++)
cin >> start[i];
for (int j = 0; j < 9; j++)
cin >> goal[j];
int num = bfs();
if (num != -1) {
cout << num << endl;
}
else
cout << "impossible" << endl;
return 0;
}
函数讲解
memcpy()
描述:将指定字符串复制到目标字符串,此函数有个数限制,与函数-strncpy用法差不多。
格式:memcpy(aim,str,n)。
swap()
在main函数中创建两个值,通过调用函数对其进行交换。