任务1:

思路:使用广度优先搜索算法,从初始棋局开始,每次将相邻的数字方块移动到空格中,并保存这个状态,直到达到目标棋局。

具体实现:

  1. 定义一个结构体,表示每个状态,包括当前棋局、空格的位置和已经移动的步数。

struct State { int board[3][3]; // 棋局 int empty_x, empty_y; // 空格位置 int steps; // 移动步数 };

  1. 定义一个队列,保存所有状态。

queue q;

  1. 定义一个标记数组,标记每个状态是否已经出现过。

bool vis[3][3][3][3][3][3][3][3];

  1. 将初始状态加入队列中。

State start; start.board = { {2, 8, 3}, {1, 6, 4}, {7, 0, 5} }; start.empty_x = 1; start.empty_y = 2; start.steps = 0; q.push(start); vis[2][8][3][1][6][4][7][0][5] = true;

  1. 在队列中循环,直到找到目标状态。

while (!q.empty()) { State cur = q.front(); q.pop(); if (cur.board == target.board) { cout << cur.steps << endl; break; } // 将相邻的数字方块移动到空格中 for (int i = 0; i < 4; i++) { int nx = cur.empty_x + dx[i], ny = cur.empty_y + dy[i]; if (nx >= 0 && nx < 3 && ny >= 0 && ny < 3) { State next = cur; swap(next.board[cur.empty_x][cur.empty_y], next.board[nx][ny]); next.empty_x = nx; next.empty_y = ny; next.steps++; // 如果这个状态没有出现过,就加入队列中 if (!vis[next.board[0][0]][next.board[0][1]][next.board[0][2]][next.board[1][0]][next.board[1][1]][next.board[1][2]][next.board[2][0]][next.board[2][1]][next.board[2][2]]) { q.push(next); vis[next.board[0][0]][next.board[0][1]][next.board[0][2]][next.board[1][0]][next.board[1][1]][next.board[1][2]][next.board[2][0]][next.board[2][1]][next.board[2][2]] = true; } } } }

完整代码:

#include #include using namespace std;

const int dx[4] = {0, 0, 1, -1}; const int dy[4] = {1, -1, 0, 0};

struct State { int board[3][3]; int empty_x, empty_y; int steps; };

int main() { State start, target; start.board = { {2, 8, 3}, {1, 6, 4}, {7, 0, 5} }; start.empty_x = 1; start.empty_y = 2; start.steps = 0; target.board = { {1, 2, 3}, {8, 0, 4}, {7, 6, 5} }; queue q; q.push(start); bool vis[3][3][3][3][3][3][3][3][3] = {false}; vis[2][8][3][1][6][4][7][0][5] = true; while (!q.empty()) { State cur = q.front(); q.pop(); if (cur.board == target.board) { cout << cur.steps << endl; break; } for (int i = 0; i < 4; i++) { int nx = cur.empty_x + dx[i], ny = cur.empty_y + dy[i]; if (nx >= 0 && nx < 3 && ny >= 0 && ny < 3) { State next = cur; swap(next.board[cur.empty_x][cur.empty_y], next.board[nx][ny]); next.empty_x = nx; next.empty_y = ny; next.steps++; if (!vis[next.board[0][0]][next.board[0][1]][next.board[0][2]][next.board[1][0]][next.board[1][1]][next.board[1][2]][next.board[2][0]][next.board[2][1]][next.board[2][2]]) { q.push(next); vis[next.board[0][0]][next.board[0][1]][next.board[0][2]][next.board[1][0]][next.board[1][1]][next.board[1][2]][next.board[2][0]][next.board[2][1]][next.board[2][2]] = true; } } } } return 0; }

任务2:

思路:在任务1的基础上,记录每个状态是从哪个状态转移过来的,最终可以通过逆推出移动序列。

具体实现:

  1. 在结构体中新增一个成员变量,表示上一个状态的索引。

struct State { int board[3][3]; int empty_x, empty_y; int steps; int prev; // 上一个状态的索引 };

  1. 在加入队列时,记录当前状态的索引。

vector states; // 保存所有状态 start.prev = -1; // 初始状态的上一个状态为-1 states.push_back(start); int cur_index = 0;

  1. 在每次找到新状态时,记录这个状态是从哪个状态转移过来的,并将这个状态加入队列中。

next.prev = cur_index; states.push_back(next); q.push(next);

  1. 在找到目标状态后,从目标状态开始逆推,直到回到初始状态,记录每个状态的移动方向。

vector directions; // 保存移动方向 int index = states.size() - 1; // 从目标状态开始逆推 while (index != 0) { // 回到初始状态 int prev_index = states[index].prev; int x1 = states[prev_index].empty_x, y1 = states[prev_index].empty_y; int x2 = states[index].empty_x, y2 = states[index].empty_y; if (x1 == x2) { if (y1 < y2) { directions.push_back(0); // 向右移动 } else { directions.push_back(1); // 向左移动 } } else { if (x1 < x2) { directions.push_back(2); // 向下移动 } else { directions.push_back(3); // 向上移动 } } index = prev_index; } reverse(directions.begin(), directions.end()); // 反转方向

完整代码:

#include #include #include #include using namespace std;

const int dx[4] = {0, 0, 1, -1}; const int dy[4] = {1, -1, 0, 0};

struct State { int board[3][3]; int empty_x, empty_y; int steps; int prev; };

int main() { State start, target; start.board = { {2, 8, 3}, {1, 6, 4}, {7, 0, 5} }; start.empty_x = 1; start.empty_y = 2; start.steps = 0; target.board = { {1, 2, 3}, {8, 0, 4}, {7, 6, 5} }; vector states; start.prev = -1; states.push_back(start); int cur_index = 0; queue q; q.push(start); bool vis[3][3][3][3][3][3][3][3][3] = {false}; vis[2][8][3][1][6][4][7][0][5] = true; while (!q.empty()) { State cur = q.front(); q.pop(); if (cur.board == target.board) { cout << cur.steps << endl; int index = states.size() - 1; vector directions; while (index != 0) { int prev_index = states[index].prev; int x1 = states[prev_index].empty_x, y1 = states[prev_index].empty_y; int x2 = states[index].empty_x, y2 = states[index].empty_y; if (x1 == x2) { if (y1 < y2) { directions.push_back(0); } else { directions.push_back(1); } } else { if (x1 < x2) { directions.push_back(2); } else { directions.push_back(3); } } index = prev_index; } reverse(directions.begin(), directions.end()); for (int d : directions) { if (d == 0) { cout << "R"; } else if (d == 1) { cout << "L"; } else if (d == 2) { cout << "D"; } else { cout << "U"; } } cout << endl; break; } for (int i = 0; i < 4; i++) { int nx = cur.empty_x + dx[i], ny = cur.empty_y + dy[i]; if (nx >= 0 && nx < 3 && ny >= 0 && ny < 3) { State next = cur; swap(next.board[cur.empty_x][cur.empty_y], next.board[nx][ny]); next.empty_x = nx; next.empty_y = ny; next.steps++; if (!vis[next.board[0][0]][next.board[0][1]][next.board[0][2]][next.board[1][0]][next.board[1][1]][next.board[1][2]][next.board[2][0]][next.board[2][1]][next.board[2][2]]) { next.prev = cur_index; states.push_back(next); q.push(next); vis[next.board[0][0]][next.board[0][1]][next.board[0][2]][next.board[1][0]][next.board[1][1]][next.board[1][2]][next.board[2][0]][next.board[2][1]][next.board[2][2]] = true; } } } cur_index++; } return 0; }

用c语言写一个八数码问题:在一个3×3的棋盘上放置编号为1~8的8个方块每个占一格另外还有一个空格。与空格相邻的数字方块可以移动到空格里。任务1:指定初始棋局和目标棋局计算出最少的移动步数;任务2:输出数码的移动序列。

原文地址: https://www.cveoy.top/t/topic/bFjx 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录