动态规划(C语言实现)


动态规划

动态规划的介绍

动态规划的定义

点这里直接跳转 - - >动态规划
简单点来说,动态规划 = 分治递归 (递推)+ 记忆存储。

什么叫做分治递归(递推)?

分治递归其实既包含了递归这种编程技巧和思维方式,又包含分而治之这种算法思想,简单点来说,递归对于一个递推式而言就是一个式子从后往前算,最前面的项是第一项(已知),我调用很多次函数,就可以拿到这个第一项,然后返回这个第一项就可以求出来其它项的值,具体的内容我们后面博客会详细的提到这个递归。

递归

1.定义

递归:(英语:Recursion),在数学和计算机科学中是指在函数的定义中使用函数自身的方法,在计算机科学中还额外指一种通过重复将问题分解为同类的子问题而解决问题的方法。

2.引入

递归的基本思想是某个函数直接或者间接地调用自身,这样原问题的求解就转换为了许多性质相同但是规模更小的子问题。求解时只需要关注如何把原问题划分成符合条件的子问题,而不需要过分关注这个子问题是如何被解决的。

以下是一些有助于理解递归的例子:
1.如何给一堆数字排序?答:分成两半,先排左半边再排右半边,最后合并就行了,至于怎么排左边和右边,请重新阅读这句话。
2.你今年几岁?答:去年的岁数加一岁,1999 年我出生。

分而治之

1.定义

定义
分治(英语:Divide and Conquer),字面上的解释是「分而治之」,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

2.过程

分治算法的核心思想就是「分而治之」。

大概的流程可以分为三步:分解 -> 解决 -> 合并。

1.分解原问题为结构相同的子问题。
2.分解到某个容易求解的边界之后,进行递归求解。
3.将子问题的解合并成原问题的解。
分治法能解决的问题一般有如下特征:

1.该问题的规模缩小到一定的程度就可以容易地解决。
2.该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质,利用该问题分解出的子问题的解可以合并为该问题的解。
3.该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

什么叫做记忆储存?

即在程序中,将某个重复出现的对象储存起来,下次用到它时,可以直接使用

斐波拉契数列的递归求法

点这里直接跳转 - - >题目—牛客网

斐波拉契数的定义

点这里直接跳转 - - >百度百科

传统的递归解法

递归的关键在于自上而下,利用公式F(n) = F(n-1)+F(n-2),n>=2。假设我们要算第5个数的斐波拉契数为多少,那么我们只需要知道第4个数和第3个数的结果就可以了,即F(5)= F(4)+F(3),按照同样的思路去算F(4)与F(3),在把值返回过来计算即可,这里我们借助图片更好的去理解。
在这里插入图片描述
代码实现如下,这里我们只给出了函数部分。

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

这种算法虽然在时间复杂度上不占优势,但分而治之的思想很值得借鉴。另外,本人才疏学浅,如有不足,请各位大佬不吝赐教,谢谢!!

动态规划解法

#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#include<assert.h>
int Fib(int n,int* p)
{
 
  p[0] = 0;
  p[1] = 1;
  if(p[n] < 0)
   p[n] = Fib(n-1,p) + Fib(n-2,p);
   return p[n]; 
}
int main() {
	
    int n = 0;
    scanf("%d",&n);
	int* p = (int*)malloc((n+1) * sizeof(int));//注意这里要开辟n+1个数组的大小,因为p[0]也要算上,否则会造成数组越界。
	assert(p);//确保p已经申请空间成功,防止出现空指针的情况
    memset(p,-1,(n+1) * sizeof(int*));//初始化动态数组的所有值为-1,方便知道F(n)是否已经算出
    printf("%d\n", Fib(n,p)); 
    return 0;
    }

感悟与思考

  • 递归来求其实并不是斐波拉契问题的最优解,递推求解更为方便,递归的思路适用于更多的情景,有些场景里面递归有着无法替代的地位,而且动态规划在找工作和面试时也是一个比较重要的板块,相信大家都已经掌握的不错了,没掌握的很好也没关系,可以去做做牛客网的在线编程题点这里直接跳转 - - >牛客网动态规划专题,另外大家对这篇博客有什么改进的地方,欢迎评论区留言,我将一一回复,谢谢大家!!
  • 16
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
活动安排问题是一个经典的动态规划问题,可以使用C语言实现。具体步骤如下: 1. 首先,将所有的活动按照结束时间从早到晚排序。 2. 定义一个数组dp,其中dp[i]表示前i个活动的最大兼容活动数。 3. 初始化dp为0。 4. 对于每个i,从i-1向前遍历所有的活动j,如果活动j的结束时间小于活动i的开始时间,则更新dp[i]为dp[j]+1和dp[i-1]中的较大值。 5. 遍历完所有的活动后,dp[n]即为最终的结果,其中n为活动总数。 下面是C语言实现的代码: ```c #include <stdio.h> #include <stdlib.h> // 活动结构体 typedef struct { int start; int end; } Activity; // 活动比较函数,按照结束时间从早到晚排序 int cmp(const void* a, const void* b) { return ((Activity*)a)->end - ((Activity*)b)->end; } // 动态规划求解活动安排问题 int activitySelection(Activity activities[], int n) { // 按照结束时间从早到晚排序 qsort(activities, n, sizeof(Activity), cmp); // 定义dp数组 int dp[n+1]; dp[0] = 0; // 动态规划求解 for (int i = 1; i <= n; i++) { dp[i] = 1; for (int j = i-1; j >= 1; j--) { if (activities[j-1].end <= activities[i-1].start) { dp[i] = dp[j] + 1 > dp[i] ? dp[j] + 1 : dp[i]; } } } // 返回最大兼容活动数 return dp[n]; } int main() { // 测试数据 Activity activities[] = {{1, 4}, {3, 5}, {0, 6}, {5, 7}, {3, 8}, {5, 9}, {6, 10}, {8, 11}, {8, 12}, {2, 13}, {12, 14}}; // 活动总数 int n = sizeof(activities) / sizeof(Activity); // 求解最大兼容活动数 int maxActivities = activitySelection(activities, n); // 输出结果 printf("最大兼容活动数为:%d\n", maxActivities); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永远热情,永远谦卑,永远真诚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值