C# 动态规划算法方法 C#如何解决斐波那契数列和背包问题

1次阅读

记忆化递归将斐波那契时间复杂度降至o(n);数组填充法用迭代实现o(1)空间;0-1背包一维dp压缩空间;二维dp显式建模便于理解;回溯法还原最优物品组合。

C# 动态规划算法方法 C#如何解决斐波那契数列和背包问题

一、使用记忆化递归求解斐波那契数列

斐波那契数列存在大量重复子问题,直接递归会导致指数级时间开销。引入字典缓存已计算结果,可将时间复杂度降至线性级别。

1、定义静态字典 private Static readonly Dictionary memo = new Dictionary();

2、编写递归方法,在每次返回前检查键是否存在,若存在则直接返回值;否则计算后存入字典并返回。

3、在方法入口处添加判断:if (memo.ContainsKey(n)) return memo[n];

4、对 n == 0 和 n == 1 的情况分别返回 0 和 1,并在计算 result = Fib(n-1) + Fib(n-2) 后执行 memo[n] = result;

二、采用自底向上数组填充法求解斐波那契数列

该方法规避递归调用开销,通过迭代方式从小到大依次计算每个斐波那契数值,仅需常数空间即可完成。

1、声明长度为 n+1 的 long 类型数组 dp = new long[n + 1];

2、初始化 dp[0] = 0,dp[1] = 1(若 n ≥ 1)。

3、使用 for 循环从 i = 2 到 i ≤ n,执行 dp[i] = dp[i – 1] + dp[i – 2];

4、返回 dp[n] 作为最终结果。

三、实现 0-1 背包问题的一维动态规划解法

利用滚动数组思想压缩空间,将二维状态转移降为一维,避免创建完整二维表,显著节省内存占用。

1、声明长度为 capacity + 1 的整型数组 dp = new int[capacity + 1];

2、外层遍历所有物品索引 i,内层从 capacity 递减至当前物品重量 weight[i]。

3、在内层循环中更新:dp[w] = math.Max(dp[w], dp[w – weight[i]] + value[i]);

4、确保每次更新不依赖本轮已被覆盖的较小下标值,从而维持状态有效性。

四、使用二维数组显式建模背包问题的状态转移

通过构建 rows = items.Length + 1、cols = capacity + 1 的二维数组,清晰呈现每一步决策过程,便于调试与理解。

1、初始化二维整型数组 dp = new int[items.Length + 1, capacity + 1];

2、外层循环 i 从 1 到 items.Length,内层循环 w 从 0 到 capacity。

3、若当前物品重量大于 w,则 dp[i, w] = dp[i – 1, w];

4、否则取两种选择的最大值:dp[i, w] = Math.Max(dp[i – 1, w], dp[i – 1, w – weight[i – 1]] + value[i – 1]);

五、应用递归回溯结合备忘录输出背包最优解的具体物品组合

在完成动态规划填表后,通过反向追踪 dp 表格路径,识别哪些物品被选中,还原出实际选取方案。

1、从位置 (items.Length, capacity) 开始回溯,设置空列表用于收集索引。

2、若 dp[i, w] != dp[i – 1, w],说明第 i-1 个物品被选中,将其加入列表,并令 w -= weight[i – 1]。

3、无论是否选取,均执行 i– 继续上一行比较。

4、当 i == 0 或 w == 0 时终止,返回逆序后的物品索引列表。

text=ZqhQzanResources