当前位置: 首页 > news >正文

千问 LeetCode 2920. 收集所有金币可获得的最大积分 C语言实现

这道题的 C 语言解法,核心思路与 Java 版本完全一致,都是采用树形动态规划(Tree DP)结合记忆化搜索。由于 C 语言没有现成的集合与动态数组库,我们需要手动使用邻接表来建树,并自行管理内存。

以下是完整的 C 语言实现:

💻 C 语言代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 定义邻接表节点
typedef struct Node {
int val;
struct Node* next;
} Node;

// 创建新的邻接表节点
Node* createNode(int val) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->val = val;
newNode->next = NULL;
return newNode;
}

// 深度优先搜索(记忆化递归)
int dfs(int i, int j, int father, int** memo, Node** graph, int* coins, int k) {
// 如果该状态已经计算过,直接返回
if (memo[i][j] != -1) {
return memo[i][j];
}

// 当前节点 i 在经过 j 次减半后的实际金币数
int currentCoin = coins[i] >> j;

// 策略1:使用方式1收集 (coins[i] >> j) - k
int res1 = currentCoin - k;

// 策略2:使用方式2收集 (coins[i] >> j) / 2
int res2 = currentCoin >> 1;

// 遍历所有子节点(排除父节点)
Node* cur = graph[i];
while (cur != NULL) {
int child = cur->val;
if (child != father) {
// 累加策略1下,子树的收益
res1 += dfs(child, j, i, memo, graph, coins, k);

// 累加策略2下,子树的收益
// 剪枝:如果 j >= 13,说明再右移一次金币肯定为0,没必要继续深入递归计算 res2
if (j < 13) {
res2 += dfs(child, j + 1, i, memo, graph, coins, k);
}
}
cur = cur->next;
}

// 记录并返回最大值
memo[i][j] = (res1 > res2) ? res1 : res2;
return memo[i][j];
}

int maximumPoints(int** edges, int edgesSize, int* edgesColSize, int* coins, int coinsSize, int k) {
int n = coinsSize;

// 1. 构建邻接表表示树
Node** graph = (Node**)malloc(n * sizeof(Node*));
for (int i = 0; i < n; i++) {
graph[i] = NULL;
}

for (int i = 0; i < edgesSize; i++) {
int x = edges[i][0];
int y = edges[i][1];
// 无向图,双向添加边
Node* nodeY = createNode(y);
nodeY->next = graph[x];
graph[x] = nodeY;

Node* nodeX = createNode(x);
nodeX->next = graph[y];
graph[y] = nodeX;
}

// 2. 初始化记忆化数组 memo[i][j]
int** memo = (int**)malloc(n * sizeof(int*));
for (int i = 0; i < n; i++) {
memo[i] = (int*)malloc(14 * sizeof(int)); // j 最大取 14 即可
for (int j = 0; j < 14; j++) {
memo[i][j] = -1; // -1 表示未计算过
}
}

// 3. 从根节点 0 开始 DFS,初始父节点为 -1,初始减半次数为 0
int result = dfs(0, 0, -1, memo, graph, coins, k);

// 4. 释放内存
// 释放邻接表
for (int i = 0; i < n; i++) {
Node* cur = graph[i];
while (cur != NULL) {
Node* temp = cur;
cur = cur->next;
free(temp);
}
}
free(graph);

// 释放记忆化数组
for (int i = 0; i < n; i++) {
free(memo[i]);
}
free(memo);

return result;
}

📊 复杂度分析
* 时间复杂度:O(N)。虽然引入了状态 j,但因为金币最多减半 14 次就会变成 0,状态总数被限制在 N times 14 以内,每个状态只计算一次。
* 空间复杂度:O(N)。用于存储邻接表、记忆化数组以及递归调用的系统栈空间。

⚠️ C 语言实现注意事项
1. 手动建树:C 语言中没有 ArrayList,我们使用了结构体 Node 配合指针来构建邻接表(链式前向星或单链表均可)。
2. 内存管理:在 C 语言中,使用 malloc 分配的二维数组和链表节点,在函数返回前必须手动 free 释放,否则会导致内存泄漏。
3. 位运算:>> 右移运算在 C 语言中对于非负整数等同于除以 2 的幂,且效率更高。
4. 边界剪枝:依然保留了 if (j < 13) 的剪枝逻辑,防止无意义的递归调用。

http://www.jsqmd.com/news/933629/

相关文章:

  • 如何快速美化foobar2000:终极界面优化完整指南
  • 别再只会用Burp抓包了:手把手教你用APIKit和Param Miner插件高效发现API端点
  • 2026年知名的江西小型海绵切割机/振动刀海绵切割机可靠供应商推荐 - 品牌宣传支持者
  • 人机协作AI:从自动化到增强化的技术演进与应用实践
  • LongCat-Flash-Lite-FP8安全与部署注意事项:MIT许可证详解与使用限制
  • 如何将Multilingual-MiniLM-L12-H384集成到现有系统中:兼容性指南
  • 2026年比较好的西安天然气石油管线管3PE防腐/L360QS酸性服役条件用管线管可靠供应商推荐 - 品牌宣传支持者
  • 2026年口碑好的2PE防腐钢管/重庆环氧树脂防腐钢管实力工厂推荐 - 行业平台推荐
  • OpenCode LSP集成架构解析:构建高效终端开发环境
  • 别再搞混了!CAPL诊断脚本里DiagSetParameterRaw和DiagSetPrimitiveByte到底怎么选?
  • 微软ATL Cairo实验室:从NLP技术栈到产品落地的长期主义实践
  • LabelImg图像标注工具:从零开始的AI数据标注完整指南
  • Halcon实战:巧用vector_field_length与local_max_sub_pix提升卫星云图粒子运动分析精度
  • 2026年评价高的江西同浴型固色剂/无醛固色剂/无酚固色剂/直接染料固色剂优质厂家推荐榜 - 品牌宣传支持者
  • 告别摄像头局限:手把手教你用激光雷达和ReID3D搭建更可靠的行人识别系统
  • 千问 LeetCode 2926. 平衡子序列的最大和 Java实现
  • 麒麟V10服务器上,毕昇JDK 1.8缺失javafx.util.Pair的快速修复指南
  • 告别C语言!用Python玩转智能车:NXP RT1021核心板+MicroPython保姆级入门指南
  • PyTorch-NPU/baichuan2_7b_base模型蒸馏技术:如何从小模型获得大模型性能
  • SAP后台配置保姆级指南:从SPRO入口到生产环境传请求,新手避坑全流程
  • 数字媒体真实性验证实战指南:从元数据到AI检测的完整工具箱
  • Campus-iMaoTai:基于Spring Boot的茅台预约自动化系统架构设计与实现
  • DeepSeek Coder 33B Instruct常见问题解决:从安装错误到推理异常的完整排查指南
  • 2026年评价高的给排水涂塑钢管/内外涂塑钢管优质供应商推荐 - 行业平台推荐
  • 如何永久保存微信聊天记录:3步掌握WeChatMsg数据备份终极指南
  • 如何用微信聊天记录打造你的专属AI记忆库:留痕项目完全指南
  • 微软翻译技术演进:从统计机器翻译到深度神经网络的服务化实践
  • SPACER求解器:Z3中模型检测与定理证明融合的程序验证引擎
  • 2026年口碑好的广东纱窗执手/平开窗执手/广东门窗执手厂家选择推荐 - 品牌宣传支持者
  • 2019数模国赛B题‘同心协力’一等奖方案:可修改论文+Matlab与Lingo双平台源码