From c3aeaedd22b6d9e2a332ea2d4f44c22ec93c5f99 Mon Sep 17 00:00:00 2001 From: m7wzyfpis <1040766652@qq.com> Date: Sun, 26 Nov 2023 23:26:48 +0800 Subject: [PATCH] =?UTF-8?q?A*=E7=AE=97=E6=B3=95=EF=BC=88=E5=AD=98=E5=9C=A8?= =?UTF-8?q?bug=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- A.cpp | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 A.cpp diff --git a/A.cpp b/A.cpp new file mode 100644 index 0000000..35cf408 --- /dev/null +++ b/A.cpp @@ -0,0 +1,288 @@ +#include +#include +#include +#include + +#define N 3 // 定义拼图的维度,这是一个3x3的拼图 + +typedef struct Node { + int puzzle[N][N]; // 存储拼图状态的数组 + struct Node* parent; // 指向父节点的指针,用于追踪路径 + int f, g, h; // A*算法中的 f, g, h 值 +} Node; + +// 创建新的拼图节点 +Node* createNode(int puzzle[N][N]) { + Node* newnode = (Node*)malloc(sizeof(Node)); + if (newnode == NULL) { + printf("Memory allocation failed!\n"); + exit(0); // 如果内存分配失败,就退出程序 + } + // 复制 puzzle 数组的值到新节点的 puzzle 数组中 + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + newnode->puzzle[i][j] = puzzle[i][j]; + } + } + newnode->parent = NULL; // 初始化 parent 节点为 NULL + newnode->f = 0; // 初始化 f 为 0 + newnode->g = 0; // 初始化 g 为 0 + newnode->h = 0; // 初始化 h 为 0 + return newnode; // 返回指向新节点的指针 +//请实现该函数 + + + +} + +// 检查两个拼图状态是否相同 +bool isSamePuzzle(int a[N][N], int b[N][N]) { + //相同则返回true,否则返回false +for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (a[i][j] != b[i][j]) { + return false; + } + } + } + return true; + + +} + +// 打印拼图状态 +void printPuzzle(int puzzle[N][N]) { + //双重for循环实现拼图的打印 + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + printf("%d ", puzzle[i][j]); // 打印每个元素,后面加一个空格 + } + + + printf("\n"); +} + + +// 启发函数,计算当前状态到目标状态的估计代价 +int heuristic(Node* current, Node* goal) { + int h = 0; + // 计算不匹配的拼图块数量 + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (current->puzzle[i][j] != goal->puzzle[i][j]) { + h++; // 如果当前节点和目标节点的拼图块不匹配,那么 h 就加 1 + } + } + } + return h; // 返回 h 的值,即不匹配的拼图块的数量 +} + +// 移动操作,生成新的拼图状态 +Node* move(Node* current, int dir) { + int key_x, key_y;//记录空白块的位置 + // 找到空白块的位置 + int new_x, new_y; // 用于记录移动后的空白块的位置 + int temp; // 用于交换拼图块的值 + bool isValidMove = false; // 标志位,表示移动是否有效 + + // 遍历 current 节点的 puzzle 数组,找到值为 0 的拼图块 + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (current->puzzle[i][j] == 0) { + key_x = i; + key_y = j; + isValidMove = true; // 表示找到了空白块,移动是可能的 + break; + } + } + if (isValidMove) break; + } + + // 如果没有找到空白块,返回 NULL + if (!isValidMove) return NULL; + + new_x = key_x; + new_y = key_y; + + // 根据移动方向更新 new_x 和 new_y 的值 + if (dir == 0 && new_x > 0) new_x--; // 上移 + else if (dir == 1 && new_x < N-1) new_x++; // 下移 + else if (dir == 2 && new_y > 0) new_y--; // 左移 + else if (dir == 3 && new_y < N-1) new_y++; // 右移 + else return NULL; // 如果新位置超出边界,返回 NULL + + // 创建新节点,复制当前拼图状态,并交换块的位置 + Node* newNode = (Node*)malloc(sizeof(Node)); + if (newNode == NULL) { + printf("Memory allocation failed!\n"); + exit(0); // 如果内存分配失败,就退出程序 + } + //给new_x、new_y赋值 + + // 根据移动方向更新新块的位置,上下左右移动 + + // 检查新位置是否在边界内 + + + // 创建新节点,复制当前拼图状态,并交换块的位置 + Node* new_node = createNode(current->puzzle); + new_node->puzzle[key_x][key_y] = current->puzzle[new_x][new_y]; + new_node->puzzle[new_x][new_y] = 0; + return new_node; +} + +// A*算法,寻找最短路径 +Node* AStar(Node* start, Node* goal) { + Node* OPEN[1000]; // 开放列表,用于存储待探索的节点 + Node* CLOSED[1000]; // 关闭列表,用于存储已探索的节点 + int OPEN_SIZE = 0; // 开放列表的大小 + int CLOSED_SIZE = 0; // 关闭列表的大小 + + OPEN[0] = start; // 将起始节点添加到开放列表 + OPEN_SIZE = 1; // 开放列表的大小设置为1 + CLOSED_SIZE = 0; // 关闭列表的大小设置为0 + + while (OPEN_SIZE > 0) {//对open列表进行操作 + int min_f = OPEN[0]->f;//初始化最小的f + int min_index = 0; + // 查找开放列表中具有最小f值的节点 + for (int i = 0; i < OPEN_SIZE; i++) { + if (OPEN[i]->f < min_f) { + min_f = OPEN[i]->f; + min_index = OPEN[i]; + } + } + + Node* current = OPEN[min_index]; // 获取具有最小f值的节点 + + // 如果当前节点与目标状态匹配,表示找到解 + if (isSamePuzzle(minNode, goal)) { + return min_index; + } + + //开放列表的大小减1,表示从开放列表中移除了一个节点 + + //将最小 f 值的节点移到开放列表的末尾,以便稍后将其添加到关闭列表中。 + for (int i = 0; i < OPEN_SIZE; i++) { + if (OPEN[i] == minNode) { + for (int j = i; j < OPEN_SIZE - 1; j++) { + OPEN[j] = OPEN[j+1]; + } + OPEN_SIZE--; + break; + } + } + //这是为了优化开放列表的结构。 + Node* temp = OPEN[min_index]; + OPEN[min_index] = OPEN[OPEN_SIZE]; + OPEN[OPEN_SIZE] = temp; + + //将当前节点添加到关闭列表,关闭列表大小加1 + CLOSED[CLOSED_SIZE] = *current; + CLOSED_SIZE++; + + int key = 0; + // 查找当前节点中空白块的位置 + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (current->puzzle[i][j] == 0) { + key = i * N + j; + break; + } + } + } + + // 尝试四个方向的移动操作 + for (int dir = 0; dir < 4; dir++) { + Node* new_node = move(current, dir); + + if (new_node != NULL && !isSamePuzzle(new_node->puzzle, current->puzzle)) { + //得到对应的g、f、h值 + int gNew = current->g + 1; + int hNew = heuristic(new_node, goal); + int fNew = gNew + hNew; + + bool in_OPEN = false; + int open_index = -1; + // 检查新节点是否在开放列表中 + for (int i = 0; i < OPEN_SIZE; i++) { + if (isSamePuzzle(new_node->puzzle, OPEN[i]->puzzle)) { + in_OPEN = true; + open_index = i; + break; + } + } + + bool in_CLOSED = false; + + // 检查新节点是否在关闭列表中 + for (int i = 0; i < CLOSED_SIZE; i++) { + if (isSamePuzzle(new_node->puzzle, CLOSED[i]->puzzle)) { + in_CLOSED = true; + break; + } + } + //若该节点机不在开放列表中也不在关闭列表中 + if (!in_OPEN && !in_CLOSED) { + //把gNew、hNew、fNew赋给new_nod对应的g、h、f值,并将其父节点设置为当前节点。 + new_node->g = gNew; + new_node->h = hNew; + new_node->f = fNew; + new_node->parent = current; + // 添加新节点new_node到开放列表,开放列表大小加1 + OPEN[OPEN_SIZE] = new_node; // 添加新节点到开放列表中 + OPEN_SIZE++; // 开放列表大小加1 + } + //如果新节点已经在开放列表中,但新的 f 值更小,将更新开放列表中已存在节点的信息。 + else if (in_OPEN && fNew < OPEN[open_index]->f) { + OPEN[open_index]->parent = current; + OPEN[open_index]->f = fNew; + } + } + } + } + + return NULL; // 无解 +} + +// 打印解路径 +void printPath(Node* final) { + if (final == NULL) { + return; + } + printPath(final->parent); // 递归打印路径 + for (int i = 0; i < N; i++) { + if (i%3==0){ + printf("-------\n"); + } + for (int j = 0; j < N; j++) { + printf("%d ", final->puzzle[i][j]); + } + + printf("\n"); + + } +} + +int main() { + //int start[N][N] = {{2, 0, 3}, {1, 8, 4}, {7, 6, 5}}; + //int target[N][N] = {{1, 2, 3}, {8, 0, 4}, {7, 6, 5}}; + + // int start[N][N] = {{2, 8, 3}, {1, 6, 4}, {7, 0, 5}}; + // int target[N][N] = {{1, 2, 3}, {8, 0, 4}, {7, 6, 5}}; + + int start[N][N] = {{2, 8, 3}, {1, 0, 4}, {7, 6, 5}}; + int target[N][N] = {{1, 2, 3}, {8, 0, 4}, {7, 6, 5}}; + Node* init = createNode(start); + Node* goal = createNode(target); + + Node* final = AStar(init, goal); + if (final) { + printf("This problem has a solution:\n"); + printPath(final); // 打印解路径 + } else { + printf("This problem has no solution!\n"); + } + + return 0; +}