mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-05 22:59:31 +08:00
@ -514,7 +514,170 @@ main()
|
||||
|
||||
### C
|
||||
|
||||
|
||||
```C
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// 定义一个结构体,表示棋盘上骑士的位置和相关的 A* 算法参数
|
||||
typedef struct {
|
||||
int x, y; // 骑士在棋盘上的坐标
|
||||
int g; // 从起点到当前节点的实际消耗
|
||||
int h; // 从当前节点到目标节点的估计消耗(启发式函数值)
|
||||
int f; // 总的估计消耗(f = g + h)
|
||||
} Knight;
|
||||
|
||||
#define MAX_HEAP_SIZE 2000000 // 假设优先队列的最大容量
|
||||
|
||||
// 定义一个优先队列,使用最小堆来实现 A* 算法中的 Open 列表
|
||||
typedef struct {
|
||||
Knight data[MAX_HEAP_SIZE];
|
||||
int size;
|
||||
} PriorityQueue;
|
||||
|
||||
// 初始化优先队列
|
||||
void initQueue(PriorityQueue *pq) {
|
||||
pq->size = 0;
|
||||
}
|
||||
|
||||
// 将骑士节点插入优先队列
|
||||
void push(PriorityQueue *pq, Knight k) {
|
||||
if (pq->size >= MAX_HEAP_SIZE) {
|
||||
// 堆已满,无法插入新节点
|
||||
return;
|
||||
}
|
||||
int i = pq->size++;
|
||||
pq->data[i] = k;
|
||||
// 上滤操作,维护最小堆的性质,使得 f 值最小的节点在堆顶
|
||||
while (i > 0) {
|
||||
int parent = (i - 1) / 2;
|
||||
if (pq->data[parent].f <= pq->data[i].f) {
|
||||
break;
|
||||
}
|
||||
// 交换父节点和当前节点
|
||||
Knight temp = pq->data[parent];
|
||||
pq->data[parent] = pq->data[i];
|
||||
pq->data[i] = temp;
|
||||
i = parent;
|
||||
}
|
||||
}
|
||||
|
||||
// 从优先队列中弹出 f 值最小的骑士节点
|
||||
Knight pop(PriorityQueue *pq) {
|
||||
Knight min = pq->data[0];
|
||||
pq->size--;
|
||||
pq->data[0] = pq->data[pq->size];
|
||||
// 下滤操作,维护最小堆的性质
|
||||
int i = 0;
|
||||
while (1) {
|
||||
int left = 2 * i + 1;
|
||||
int right = 2 * i + 2;
|
||||
int smallest = i;
|
||||
if (left < pq->size && pq->data[left].f < pq->data[smallest].f) {
|
||||
smallest = left;
|
||||
}
|
||||
if (right < pq->size && pq->data[right].f < pq->data[smallest].f) {
|
||||
smallest = right;
|
||||
}
|
||||
if (smallest == i) {
|
||||
break;
|
||||
}
|
||||
// 交换当前节点与最小子节点
|
||||
Knight temp = pq->data[smallest];
|
||||
pq->data[smallest] = pq->data[i];
|
||||
pq->data[i] = temp;
|
||||
i = smallest;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
// 判断优先队列是否为空
|
||||
int isEmpty(PriorityQueue *pq) {
|
||||
return pq->size == 0;
|
||||
}
|
||||
|
||||
// 启发式函数:计算从当前位置到目标位置的欧几里得距离的平方(避免开方,提高效率)
|
||||
int heuristic(int x, int y, int goal_x, int goal_y) {
|
||||
int dx = x - goal_x;
|
||||
int dy = y - goal_y;
|
||||
return dx * dx + dy * dy; // 欧几里得距离的平方
|
||||
}
|
||||
|
||||
// 用于记录从起点到棋盘上每个位置的最小移动次数
|
||||
int moves[1001][1001];
|
||||
|
||||
// 骑士在棋盘上的8个可能移动方向
|
||||
int dir[8][2] = {
|
||||
{-2, -1}, {-2, 1}, {-1, 2}, {1, 2},
|
||||
{2, 1}, {2, -1}, {1, -2}, {-1, -2}
|
||||
};
|
||||
|
||||
// 使用 A* 算法寻找从起点到目标点的最短路径
|
||||
int astar(int start_x, int start_y, int goal_x, int goal_y) {
|
||||
PriorityQueue pq;
|
||||
initQueue(&pq);
|
||||
|
||||
// 初始化 moves 数组,-1 表示未访问过的位置
|
||||
memset(moves, -1, sizeof(moves));
|
||||
moves[start_x][start_y] = 0; // 起点位置的移动次数为 0
|
||||
|
||||
// 初始化起始节点
|
||||
Knight start;
|
||||
start.x = start_x;
|
||||
start.y = start_y;
|
||||
start.g = 0;
|
||||
start.h = heuristic(start_x, start_y, goal_x, goal_y);
|
||||
start.f = start.g + start.h; // 总的估计消耗
|
||||
|
||||
push(&pq, start); // 将起始节点加入优先队列
|
||||
|
||||
while (!isEmpty(&pq)) {
|
||||
Knight current = pop(&pq); // 取出 f 值最小的节点
|
||||
|
||||
// 如果已经到达目标位置,返回所需的最小移动次数
|
||||
if (current.x == goal_x && current.y == goal_y) {
|
||||
return moves[current.x][current.y];
|
||||
}
|
||||
|
||||
// 遍历当前节点的所有可能移动方向
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int nx = current.x + dir[i][0];
|
||||
int ny = current.y + dir[i][1];
|
||||
|
||||
// 检查新位置是否在棋盘范围内且未被访问过
|
||||
if (nx >= 1 && nx <= 1000 && ny >= 1 && ny <= 1000 && moves[nx][ny] == -1) {
|
||||
moves[nx][ny] = moves[current.x][current.y] + 1; // 更新移动次数
|
||||
|
||||
// 创建新节点,表示骑士移动到的新位置
|
||||
Knight neighbor;
|
||||
neighbor.x = nx;
|
||||
neighbor.y = ny;
|
||||
neighbor.g = current.g + 5; // 每次移动的消耗为 5(骑士移动的距离平方)
|
||||
neighbor.h = heuristic(nx, ny, goal_x, goal_y);
|
||||
neighbor.f = neighbor.g + neighbor.h;
|
||||
|
||||
push(&pq, neighbor); // 将新节点加入优先队列
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1; // 如果无法到达目标位置,返回 -1
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
scanf("%d", &n);
|
||||
while (n--) {
|
||||
int a1, a2, b1, b2; // 起点和目标点的坐标
|
||||
scanf("%d %d %d %d", &a1, &a2, &b1, &b2);
|
||||
|
||||
int result = astar(a1, a2, b1, b2); // 使用 A* 算法计算最短路径
|
||||
printf("%d\n", result); // 输出最小移动次数
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user