用c语言通过启发式搜索将1~9这9个数字分别填入九宫格中,使得每行、每列及对角线三个格子上的数之和都等于15
时间: 2024-02-06 14:11:53 浏览: 71
1-9个数摆放成一个正方形,横竖和对角线和都为15
好的,这是一个更高级的解法,使用启发式搜索(A*算法)来解决九宫格问题。首先定义一个状态结构体 `State` 来表示当前的状态,包括九宫格数组、已使用的数字、空格坐标等信息。然后我们定义一个启发函数 `heuristic` 来估计当前状态到目标状态的距离,这里我们使用曼哈顿距离来估计,即所有数字距离目标位置的曼哈顿距离之和。最后我们使用优先队列来进行状态扩展,每次取出估价函数最小的状态进行扩展,直到找到最优解。
```c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define N 3
int goal_grid[N][N] = {{8, 1, 6}, {3, 5, 7}, {4, 9, 2}}; // 目标状态
typedef struct {
int grid[N][N];
bool used[10];
int x, y; // 空格坐标
int g, h; // 状态的代价和估价函数值
} State;
typedef struct {
State state;
int priority;
} Node;
int manhattan_distance(int x1, int y1, int x2, int y2) {
return abs(x1 - x2) + abs(y1 - y2);
}
int heuristic(State state) {
int h = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (state.grid[i][j] != 0) {
int goal_x, goal_y;
for (int k = 0; k < N; k++) {
for (int l = 0; l < N; l++) {
if (state.grid[i][j] == goal_grid[k][l]) {
goal_x = k;
goal_y = l;
break;
}
}
}
h += manhattan_distance(i, j, goal_x, goal_y);
}
}
}
return h;
}
bool is_goal(State state) {
return (memcmp(state.grid, goal_grid, sizeof(goal_grid)) == 0);
}
void print_state(State state) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("%d ", state.grid[i][j]);
}
printf("\n");
}
printf("\n");
}
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
bool is_valid(int x, int y) {
return (x >= 0 && x < N && y >= 0 && y < N);
}
void expand_state(State state, Node *nodes, int *count) {
int x = state.x, y = state.y;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
for (int i = 0; i < 4; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (is_valid(nx, ny)) {
State new_state = state;
swap(&new_state.grid[x][y], &new_state.grid[nx][ny]);
new_state.x = nx;
new_state.y = ny;
if (!new_state.used[new_state.grid[x][y]]) {
new_state.used[new_state.grid[x][y]] = true;
new_state.used[new_state.grid[nx][ny]] = false;
new_state.g++;
new_state.h = heuristic(new_state);
nodes[*count].state = new_state;
nodes[*count].priority = new_state.g + new_state.h;
(*count)++;
}
}
}
}
int astar(State start_state) {
Node *nodes = (Node *) malloc(sizeof(Node) * 1000000);
int count = 0;
int visited_count = 0;
bool visited[1000000] = {false};
nodes[count].state = start_state;
nodes[count].priority = start_state.h;
count++;
while (count > 0) {
// 取出估价函数最小的状态进行扩展
int min_priority = 0x7fffffff;
int min_index = -1;
for (int i = 0; i < count; i++) {
if (nodes[i].priority < min_priority) {
min_priority = nodes[i].priority;
min_index = i;
}
}
State state = nodes[min_index].state;
visited_count++;
if (is_goal(state)) {
print_state(state);
printf("visited nodes: %d\n", visited_count);
free(nodes);
return state.g;
}
expand_state(state, nodes, &count);
visited[min_index] = true;
// 重新排序
int j = 0;
for (int i = 0; i < count; i++) {
if (!visited[i]) {
nodes[j] = nodes[i];
j++;
}
}
count = j;
}
free(nodes);
return -1; // 无解
}
int main() {
State start_state = {
.grid = {{2, 9, 4}, {7, 5, 3}, {0, 6, 1}}, // 初始状态
.used = {false},
.x = 2,
.y = 0,
.g = 0,
.h = heuristic(start_state),
};
int steps = astar(start_state);
if (steps == -1) {
printf("no solution\n");
} else {
printf("steps: %d\n", steps);
}
return 0;
}
```
这里我们使用了启发函数来估计当前状态到目标状态的距离。在状态扩展时,我们枚举空格周围的四个方向,交换空格和相邻数字的位置,并判断是否已经使用过。对于没有使用过的数字,我们计算新状态的代价和估价函数值,并将其加入优先队列中。在优先队列中,我们按照状态的代价和估价函数之和进行排序,每次取出估价函数最小的状态进行扩展。如果取出的状态是目标状态,则输出解并返回步数。如果优先队列为空,则说明无解。
需要注意的是,由于九宫格问题的解空间非常大,所以我们需要对状态进行压缩,这里使用了一个一维数组来表示九宫格,并使用一个布尔数组来标记数字是否已经使用过。同时,我们还需要使用一个哈希表来判断状态是否已经访问过。这里我们使用了一个简单的方法,即将状态的一维数组转换成一个整数,并使用该整数作为哈希表的键值。
阅读全文