[C语言]给定一个整数数组A。定义B[i]=A[0]∗...∗A[i−1]∗A[i+1]∗...∗A[n−1]B[i]=A[0]∗...∗A[i−1]∗A[i+1]∗...∗A[n−1], 计算B。

C++函数计算数组中除自身外的元素乘积
本文介绍了一个C++函数`productExceptSelf`,用于计算给定整数数组中除自身以外元素的乘积,通过两次遍历实现左右互乘的方法。

输入:A = [1, 2, 3]

输出:[6, 3, 2]

解释:B[0] = A[1] * A[2] = 6; B[1] = A[0] * A[2] = 3; B[2] = A[0] * A[1] = 2

//除自身以外数组的乘积
//左右互乘法
#include<stdlib.h>
int* productExceptSelf(int* nums) {
    numsSize = cvector_size(nums);
    int* ptr;
    ptr = (int*)malloc(sizeof(int) * numsSize);
    if (NULL == ptr)
    {
        perror("ptr == NULL!");
        return 0;
    }
    int mul = 1;
    int i = 0;
    for (i = 0; i < numsSize; i++)
    {
        ptr[i] = mul;
        mul *= nums[i];
    }
    mul = 1;
    for (i = numsSize - 1; i >= 0; i--)
    {
        ptr[i] *= mul;
        mul *= nums[i];
    }
    return ptr;
}

#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> #include <limits.h> #include <string.h> #define MAX_SIZE 100 // 定义节点结构 typedef struct Node { int x, y; // 节点坐标 int f, g, h; // A*算法的评估值(f = g + weight*h) struct Node* parent; // 父节点指针 } Node; // 定义开放列表和关闭列表(存储节点指针) Node* openList[MAX_SIZE * MAX_SIZE]; Node* closeList[MAX_SIZE * MAX_SIZE]; int openSize = 0, closeSize = 0; // 迷宫结构 char maze[MAX_SIZE][MAX_SIZE]; char mazeCopy[MAX_SIZE][MAX_SIZE]; // 用于保存原始迷宫(避免路径标记污染原始数据) int rows, cols; Node* start = NULL; Node* end = NULL; // 方向数组:上、右、下、左(仅直角移动) int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1}; // 函数声明 void readMaze(); Node* createNode(int x, int y); int isValid(int x, int y); int isObstacle(int x, int y); int isDestination(Node* current); void addToOpenList(Node* node); void addToCloseList(Node* node); Node* findInOpenList(int x, int y); // 修复:返回开放列表中的旧节点指针 int isInCloseList(int x, int y); // 优化:直接用坐标判断,避免创建临时节点 Node* popMinFromOpenList(); int manhattanDistance(Node* a, Node* b); int euclideanDistance(Node* a, Node* b); void tracePath(Node* node); void aStar(int heuristic, float weight); void freeMemory(); // 读取迷宫(同时保存原始副本) void readMaze() { // printf("请输入迷宫的行数和列数: "); scanf("%d %d", &rows, &cols); getchar(); // 消耗换行符 // printf("请输入迷宫地图(%d行,每行%d个字符,0=通路,1=障碍,S=起点,E=终点):\n", rows, cols); for (int i = 0; i < rows; i++) { // 读取一行并去除换行符 fgets(maze[i], MAX_SIZE, stdin); maze[i][strcspn(maze[i], "\n")] = '\0'; // 保存原始迷宫副本(用于路径标记) strcpy(mazeCopy[i], maze[i]); // 查找起点和终点 for (int j = 0; j < cols; j++) { if (maze[i][j] == 'S') { start = createNode(i, j); } else if (maze[i][j] == 'E') { end = createNode(i, j); } } } } // 创建新节点 Node* createNode(int x, int y) { Node* node = (Node*)malloc(sizeof(Node)); if (node == NULL) { printf("内存分配失败!\n"); exit(1); } node->x = x; node->y = y; node->f = 0; node->g = 0; node->h = 0; node->parent = NULL; return node; } // 检查坐标是否在迷宫内 int isValid(int x, int y) { return (x >= 0 && x < rows && y >= 0 && y < cols); } // 检查是否是障碍物 int isObstacle(int x, int y) { return maze[x][y] == '1'; } // 检查是否是目标节点 int isDestination(Node* current) { return (current->x == end->x && current->y == end->y); } // 添加节点到开放列表 void addToOpenList(Node* node) { if (openSize >= MAX_SIZE * MAX_SIZE) { printf("开放列表已满!\n"); return; } openList[openSize++] = node; } // 添加节点到关闭列表 void addToCloseList(Node* node) { if (closeSize >= MAX_SIZE * MAX_SIZE) { printf("关闭列表已满!\n"); return; } closeList[closeSize++] = node; } // 在开放列表中查找指定坐标的节点(返回节点指针,未找到返回NULL) Node* findInOpenList(int x, int y) { for (int i = 0; i < openSize; i++) { if (openList[i]->x == x && openList[i]->y == y) { return openList[i]; } } return NULL; } // 检查指定坐标的节点是否在关闭列表中(返回1=存在,0=不存在) int isInCloseList(int x, int y) { for (int i = 0; i < closeSize; i++) { if (closeList[i]->x == x && closeList[i]->y == y) { return 1; } } return 0; } // 从开放列表中弹出f值最小的节点(核心:维护A*的优先级) Node* popMinFromOpenList() { if (openSize == 0) { return NULL; } // 找到f值最小的节点索引 int minIndex = 0; for (int i = 1; i < openSize; i++) { if (openList[i]->f < openList[minIndex]->f) { minIndex = i; } } // 保存最小f值节点,并从开放列表中移除 Node* minNode = openList[minIndex]; for (int i = minIndex; i < openSize - 1; i++) { openList[i] = openList[i + 1]; // 前移覆盖 } openSize--; return minNode; } // 启发函数1:曼哈顿距离(适合直角移动,可采纳性强) int manhattanDistance(Node* a, Node* b) { return abs(a->x - b->x) + abs(a->y - b->y); } // 启发函数2:欧几里得距离(适合允许对角线移动,此处作对比) int euclideanDistance(Node* a, Node* b) { int dx = a->x - b->x; int dy = a->y - b->y; return (int)sqrt(dx * dx + dy * dy); // 转换为整数便于f值计算 } // 追踪并显示路径(使用迷宫副本,避免污染原始输入) void tracePath(Node* node) { if (node == NULL) { return; } int pathLength = 0; Node* temp = node; // 1. 回溯路径,统计长度(从终点到起点) while (temp != NULL) { pathLength++; temp = temp->parent; } pathLength--; // 减去起点本身(路径长度=步数) // 2. 标记路径(用'*'标记,跳过起点S和终点E) temp = node; while (temp != NULL) { if (mazeCopy[temp->x][temp->y] != 'S' && mazeCopy[temp->x][temp->y] != 'E') { mazeCopy[temp->x][temp->y] = '*'; } temp = temp->parent; } // 3. 打印带路径的迷宫 printf("\n===== 路径结果 ====="); printf("\n路径长度: %d 步", pathLength); printf("\n带路径的迷宫:\n"); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { printf("%c ", mazeCopy[i][j]); } printf("\n"); } } //请在此处添加代码完成任务 //##################Begin################## // A*算法核心实现(支持标准A*和加权A*,可切换启发函数) void aStar(int heuristic, float weight) { // 初始化列表(避免多次调用时残留数据) openSize = 0; closeSize = 0; memset(openList, 0, sizeof(openList)); memset(closeList, 0, sizeof(closeList)); // 初始化起点:g=0(起点到自身代价为0) int expandedNodes = 0; // 统计扩展节点数(搜索效率指标) while (openSize > 0) { // 1. 取出开放列表中f值最小的节点(A*核心逻辑) // 2. 检查是否到达终点:到达则追踪路径并返回 // 3. 将当前节点加入关闭列表(标记为已扩展) // 4. 遍历四个方向的邻居节点 // 5. 计算邻居节点的临时g值(当前g+1,每步代价为1) } // 开放列表为空仍未找到终点 → 无路径 printf("\n未找到路径!\n"); } //###################End################### // 释放所有动态分配的内存(避免内存泄漏) void freeMemory() { // 释放开放列表中的节点 for (int i = 0; i < openSize; i++) { if (openList[i] != NULL) { free(openList[i]); openList[i] = NULL; } } // 释放关闭列表中的节点(start和end已在列表中,无需单独释放) for (int i = 0; i < closeSize; i++) { if (closeList[i] != NULL) { free(closeList[i]); closeList[i] = NULL; } } // 重置指针(避免野指针) start = NULL; end = NULL; } int main() { int heuristic; float weight; // 1. 读取迷宫输入 readMaze(); // 2. 选择算法参数(启发函数+权重) // printf("\n===== 算法参数设置 ====="); do { // printf("\n选择启发函数 (1:曼哈顿距离, 2:欧几里得距离): "); scanf("%d", &heuristic); } while (heuristic != 1 && heuristic != 2); // 输入校验 // printf("输入权重w (标准A*算法输入1.0,加权A*输入>1.0的值): "); scanf("%f", &weight); if (weight <= 0) { printf("权重无效,自动设置为1.0(标准A*)\n"); weight = 1.0; } // 3. 执行A*算法并计时 printf("\n===== 算法执行 ====="); clock_t startTime = clock(); aStar(heuristic, weight); clock_t endTime = clock(); double runTime = (double)(endTime - startTime) / CLOCKS_PER_SEC; // 4. 输出运行时间 printf("运行时间: %.4f 秒\n", runTime); // 5. 释放内存(避免内存泄漏) freeMemory(); return 0; }任务描述 迷宫路径规划是人工智能领域中路径搜索的经典问题。本任务要求使用 A * 算法及其变体实现迷宫中从起点到终点的路径规划,并通过不同参数设置分析算法性能。 具体任务: 实现标准 A * 算法,使用两种不同的启发函数(曼哈顿距离和欧几里得距离) 实现加权 A算法(Weighted A),通过调整权重参数 w 分析其影响 对比不同算法和参数设置下的路径规划结果,包括路径长度、搜索效率和解的质量 迷宫表示为二维网格,其中: 0 表示可通行区域 1 表示障碍物 S 表示起点 E表示终点 相关知识 为了完成本关任务,你需要掌握: A * 算法原理 启发函数 加权 A * 算法 数据结构 A * 算法原理 A* 搜索算法(A* search algorithm,A* 读作 A-star),简称 A* 算法,是一种在带权有向图上,找到给定起点与终点之间的最短路径的算法。它属于图遍历(graph traversal)和最佳优先搜索算法(best-first search),亦是 BFS 的改进。 过程 A* 算法的目标是找到有向图上从起点s到终点t的最短路径。设d(x,y)为结点x与y之间的距离,也就是它们之间最短路径的长度。 记g(x)=d(s,x)为从起点s到结点x的距离函数,h∗(x)为从结点x到终点t的距离函数,h(x)为h∗(x)的一个估计。最后,记从s出发经由x到达t的最短路径长度的估计为 f(x)=g(x)+h(x) 搜索时,A* 算法每次从优先队列中取出一个f最小的结点。然后,将它的所有后继结点x都推入优先队列中,并利用实际记录的g(x)和估计的h(x)更新f(x)。 #伪代码:A*(A-Star)启发式搜索算法 # 目标:在一个二维迷宫中,从起点 start 寻找到终点 end 的最短路径 # 说明:A* 是一种结合了“实际代价(g)”和“预估代价(h)”的最优搜索算法 # 启发函数 h 使用“曼哈顿距离”(适合四向移动的格子地图) astar(maze, start, end) { # 启发函数:返回两点间的曼哈顿距离 function heuristic(a, b) { return abs(a.x - b.x) + abs(a.y - b.y) } # 四个基本移动方向:上、下、左、右 dirs = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 初始化阶段 open_heap = new min_heap() # 优先队列(最小堆),按 f 值排序 open_heap.push((0, start)) # 起点的 f = 0 came_from[start] = NULL # 记录每个节点的前驱,用于回溯路径 g_score[start] = 0 # 起点到自身的代价为 0 # 主循环:当开放列表不为空时持续搜索 while (!open_heap.empty()) { (f, current) = open_heap.pop_min() # 取出 f 值最小的节点 # 若当前节点为终点,则回溯路径并返回 if (current == end) { path = new list() while (current != NULL) { path.push_front(current) # 从终点反向压入路径 current = came_from[current] # 沿前驱回溯 } return path # 返回从起点到终点的完整路径 } # 遍历当前节点的所有邻居节点 for each (dx, dy) in dirs { neighbor = (current.x + dx, current.y + dy) # 检查邻居是否在迷宫范围内,且可通行(0 表示可走,1 表示障碍) if (0 <= neighbor.x < maze.rows and 0 <= neighbor.y < maze.cols and maze[neighbor.x][neighbor.y] == 0) { new_g = g_score[current] + 1 # 当前节点代价 + 1(每步代价固定为1) # 若邻居未访问过,或发现更优路径(代价更小) if (neighbor not in g_score or new_g < g_score[neighbor]) { g_score[neighbor] = new_g f_score = new_g + heuristic(neighbor, end) # f = g + h open_heap.push((f_score, neighbor)) # 将邻居加入开放列表 came_from[neighbor] = current # 记录前驱节点 } } } } # 若开放列表耗尽仍未到达终点,则无可行路径 return NULL } 变量说明: maze[x][y] —— 二维迷宫矩阵,0 表示可通行,1 表示障碍 start, end —— 起点与终点坐标(x, y) dirs[] —— 四个移动方向 open_heap —— 按 f 值(f = g + h)排序的最小堆(优先队列) g_score[node] —— 起点到该节点的实际代价 heuristic(a, b) —— 启发式估计函数(预估从 a 到 b 的距离) came_from[node] —— 每个节点的前驱,用于回溯路径 核心思想: A* = Dijkstra + 启发式搜索 g(n):起点到当前节点 n 的实际代价 h(n):从节点 n 到目标节点的估计代价 f(n) = g(n) + h(n) 算法每次从 open_heap 中选取 f 最小的节点扩展,从而高效地逼近目标 启发函数 启发函数用于估计当前节点到目标节点的代价,引导搜索算法优先探索更可能接近目标的路径,提高搜索效率。 曼哈顿距离:h(n)=∣x1−x2∣+∣y1−y2∣(适合网格中只能直角移动的情况) 欧几里得距离:h(n)=√[(x1−x2)²+(y1−y2)²](适合允许对角线移动的情况) 启发函数需满足可采纳性(不会高估实际代价)以保证 A * 算法找到最优解 加权 A * 算法 评估函数:f(n)=g(n)+w・h(n),其中 w 是权重参数 当 w>1 时,算法更依赖启发信息,可能找到次优解但搜索速度更快 当 w=1 时,即为标准 A * 算法 当 0<w<1 时,算法更接近 Dijkstra 算法 数据结构 开放列表(Open List):存储待扩展的节点,通常用优先队列实现 封闭列表(Closed List):存储已扩展的节点,用于避免重复搜索 编程要求 需补充的代码位置起始行数为:218 用 C 语言实现标准 A算法和加权 A算法 实现两种启发函数:曼哈顿距离和欧几里得距离 程序需接收迷宫数据作为输入,输出以下信息: 是否找到路径 路径长度(步数) 扩展节点数量(搜索效率指标) 路径的可视化表示 算法运行时间(可选) 允许用户设置加权 A * 算法的权重参数 w 对比不同算法和参数设置的性能差异 测试说明 平台会对你编写的代码进行测试: 测试输入: 迷宫的行数和列数:5 5 迷宫地图: S0000 11110 00000 01111 0000E 选择启发函数 (1:曼哈顿距离, 2:欧几里得距离):1 输入权重w (标准A算法输入1.0,加权A输入>1.0的值): 1.0 预期输出: ===== 算法执行 ===== 扩展节点数: 17 ===== 路径结果 ===== 路径长度: 16 步 带路径的迷宫: S * * * * 1 1 1 1 * * * * * * * 1 1 1 1 * * * * E 运行时间: 0.0001
10-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值