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

c++中的斐波那契数列(Fibonacci Sequence)和背包问题(Knapsack Problem)

前言

hello,大家好啊,我是文宇,不是文字,是文宇哦。

斐波那契数列(Fibonacci Sequence)

斐波那契数列(Fibonacci Sequence)是一个经典的数学问题,其中每个数都是前两个数的和。在C++中,我们可以使用多种算法来计算斐波那契数列,下面我将详细介绍每个算法的实现和优缺点。

递归算法

递归算法是最直观和简单的方法来实现斐波那契数列。通过递归调用函数来计算每一个数。具体实现如下:

int fibonacci(int n) {if (n <= 1) {return n;}return fibonacci(n - 1) + fibonacci(n - 2);
}

递归算法的优点是简洁易懂,容易理解。但是它的缺点是重复计算量大,在计算较大的斐波那契数时,可能会导致性能问题。

迭代算法

 为了避免递归算法的重复计算,我们可以使用迭代算法来计算斐波那契数列。迭代算法的基本思路是从前往后依次计算每一个数,保存中间结果。具体实现如下:

int fibonacci(int n) {if (n <= 1) {return n;}int a = 0;int b = 1;int c;for (int i = 2; i <= n; i++) {c = a + b;a = b;b = c;}return c;
}

迭代算法的优点是避免了递归算法的重复计算,性能相对较好。但是它的缺点是需要编写较多的代码,可读性稍差。

数组算法

 我们还可以使用数组来保存斐波那契数列的中间结果,以进一步提高性能。具体实现如下:

int fibonacci(int n) {if (n <= 1) {return n;}int* fib = new int[n + 1];fib[0] = 0;fib[1] = 1;for (int i = 2; i <= n; i++) {fib[i] = fib[i - 1] + fib[i - 2];}int result = fib[n];delete[] fib;return result;
}

数组算法的优点是性能较好,同时代码相对简单。但是它的缺点是需要额外的内存空间来保存数组,可能导致内存泄漏。

公式算法

在斐波那契数列的研究中,我们还发现了一个通项公式来直接计算第n个斐波那契数。具体公式如下:

int fibonacci(int n) {double goldenRatio = (1 + sqrt(5)) / 2;return round(pow(goldenRatio, n) / sqrt(5));
}

公式算法的优点是计算简单快速,但是它的缺点是可能会有精度问题,同时不太容易理解。

综上所述,以上四种算法都可以用来实现斐波那契数列。具体选择哪种算法取决于实际需求和性能要求。如果不考虑性能,递归算法是最简单直观的方法;如果性能较重要,迭代算法和数组算法可以提供较好的性能;如果要求精确计算,公式算法是一个很好的选择。

背包问题(Knapsack Problem)

背包问题(Knapsack Problem)是一个经典的组合优化问题,在计算机科学领域中被广泛研究和应用。它的基本问题可以描述为,给定一个背包的容量和一系列物品的重量和价值,如何选择物品放入背包中,使得背包中物品的总价值最大。

在C++中,我们可以使用多种算法来解决背包问题,下面我将详细介绍每个算法的实现和优缺点。

  1. 0/1背包问题: 0/1背包问题是背包问题中最基本的形式,其中每个物品要么完全放入背包,要么完全不放入。我们可以使用动态规划来解决0/1背包问题。具体算法如下:
int knapsack01(vector<int>& weights, vector<int>& values, int capacity) {int n = weights.size();vector<vector<int>> dp(n + 1, vector<int>(capacity + 1, 0));for (int i = 1; i <= n; i++) {for (int j = 1; j <= capacity; j++) {if (weights[i - 1] > j) {dp[i][j] = dp[i - 1][j];} else {dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);}}}return dp[n][capacity];
}

0/1背包问题的关键是构建一个二维的动态规划数组,利用前一个状态的结果来更新当前状态。它的优点是能够得到精确的解,但是它的缺点是时间复杂度较高,需要O(n * capacity)的时间和空间。

  1. 完全背包问题: 完全背包问题是背包问题中的一个变种,其中每个物品可以无限次地放入背包。我们同样可以使用动态规划来解决完全背包问题。具体算法如下:
int knapsackComplete(vector<int>& weights, vector<int>& values, int capacity) {int n = weights.size();vector<int> dp(capacity + 1, 0);for (int i = 0; i < n; i++) {for (int j = weights[i]; j <= capacity; j++) {dp[j] = max(dp[j], dp[j - weights[i]] + values[i]);}}return dp[capacity];
}

完全背包问题与0/1背包问题的区别在于内层循环的顺序,我们需要从小到大遍历容量,而不是从大到小。它的优点是时间复杂度相对较低,只需要O(n * capacity)的时间和O(capacity)的空间。

  1. 多重背包问题: 多重背包问题是背包问题中的另一种变种,其中每个物品有一个数量限制。我们可以使用动态规划来解决多重背包问题,类似于0/1背包问题。具体算法如下:
int knapsackMultiple(vector<int>& weights, vector<int>& values, vector<int>& quantities, int capacity) {int n = weights.size();vector<vector<int>> dp(n + 1, vector<int>(capacity + 1, 0));for (int i = 1; i <= n; i++) {for (int j = 1; j <= capacity; j++) {for (int k = 0; k <= quantities[i - 1] && k * weights[i - 1] <= j; k++) {dp[i][j] = max(dp[i][j], dp[i - 1][j - k * weights[i - 1]] + k * values[i - 1]);}}}return dp[n][capacity];
}

多重背包问题与0/1背包问题的区别在于内层循环的次数,我们需要遍历每个物品的数量限制。它的优点是能够解决具有数量限制的背包问题,但是它的缺点是时间复杂度较高,需要O(n * quantity * capacity)的时间和空间。

  1. 分数背包问题: 分数背包问题是背包问题中的一种特殊情况,其中每个物品可以被分割成任意大小的部分。我们可以使用贪心算法来解决分数背包问题,基于物品的单位价值进行排序,然后依次选择单位价值最高的物品放入背包中,直到背包没有空间为止。具体算法如下:
double knapsackFractional(vector<int>& weights, vector<int>& values, int capacity) {int n = weights.size();vector<pair<double, int>> ratios(n);for (int i = 0; i < n; i++) {ratios[i] = {static_cast<double>(values[i]) / weights[i], i};}sort(ratios.rbegin(), ratios.rend()); // 按照单位价值降序排序double result = 0.0;for (int i = 0; i < n; i++) {int index = ratios[i].second;if (weights[index] <= capacity) {result += values[index];capacity -= weights[index];} else {result += capacity * ratios[i].first;break;}}return result;
}

分数背包问题的优点是时间复杂度较低,只需要O(n * log(n))的时间和O(n)的空间,但是它的缺点是不能得到精确的解。

综上所述,以上四种算法都可以用来解决不同形式的背包问题。具体选择哪种算法取决于实际需求和性能要求。如果物品数量较少且要求精确解,可以使用0/1背包算法;如果物品数量较多或者需要更高的性能,可以使用完全背包算法;如果需要考虑物品的数量限制,可以使用多重背包算法;如果物品可以被分割成任意大小,可以使用分数背包算法。

结语

今天的算法是动态规划,脑子有点不好使了。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 3. 类的生命周期
  • 深度学习loss
  • 【QT】QT 窗口(菜单栏、工具栏、状态栏、浮动窗口、对话框)
  • 在KubeSphere 容器中快速部署使用 GitLab 并构建 DevOps 项目
  • 使用法国云手机进行面向法国的社媒营销
  • Python 潮流周刊#62:试用自由线程 Python(摘要)
  • 源码编译构建LAMP
  • string indices must be integers
  • 浏览器打开抽奖系统html
  • 怎么使用github上传XXX内所有文件
  • springboot给属性赋值的两种方式(yaml与properties)
  • 大学生算法高等数学学习平台设计方案 (第一版)
  • 昇思25天学习打卡营第22天|CV-Vision Transformer图像分类
  • MySQL 和 SQL Server 中的连表更新 UPDATE JOIN 写法比较
  • Webshell管理工具:AntSword(中国蚁剑)
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • 2017前端实习生面试总结
  • create-react-app项目添加less配置
  • css系列之关于字体的事
  • Fastjson的基本使用方法大全
  • Java 多线程编程之:notify 和 wait 用法
  • MySQL-事务管理(基础)
  • PHP的类修饰符与访问修饰符
  • SQLServer插入数据
  • SwizzleMethod 黑魔法
  • XForms - 更强大的Form
  • 半理解系列--Promise的进化史
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 深度解析利用ES6进行Promise封装总结
  • 微服务框架lagom
  • 我与Jetbrains的这些年
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • Java数据解析之JSON
  • #{}和${}的区别?
  • #FPGA(基础知识)
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (2)Java 简介
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (南京观海微电子)——示波器使用介绍
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)创业家杂志:UCWEB天使第一步
  • (转载)Google Chrome调试JS
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .Net 6.0 处理跨域的方式
  • .NET Compact Framework 多线程环境下的UI异步刷新
  • .NET委托:一个关于C#的睡前故事
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • /bin/bash^M: bad interpreter: No such file or directory
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • @Builder用法
  • [.NET 即时通信SignalR] 认识SignalR (一)
  • [20171102]视图v$session中process字段含义
  • [52PJ] Java面向对象笔记(转自52 1510988116)