什么是动态编程?
介绍
今天,在本教程中,我们将讨论动态编程的概念。
这是一种更好的编程方法。
动态编程
从理论上讲,动态编程是一种解决问题的技术,它通过将问题分成子问题来解决。
当子问题相同且相互依赖时,动态编程就会出现。
它与解决问题的"分而治之"方法非常相似。
但是在某些情况下,分而治之技术可能多次执行某些操作或者任务(增加时间复杂度)。
因此,动态编程方法(DP)通常用于优化特定问题。
此外,DP遵循最优性原则,该原则指出,对于最优决策序列,每个子序列也必须是最优的。
示例–使用DP的斐波那契
现在我们已经讨论了动态编程的基本概念,让我们看一下如何使用这种方法解决问题。
在下面的示例中,我们尝试计算斐波那契数列中位置" n"(用户输入)处的数字。
如您所知,斐波那契数列看起来像这样,
0、1、1、2、3、5、8…最多n个词。
其中起始两位数字是0和1。
让我们编写一个程序,根据用户输入在斐波那契数列的特定点自动找到正确的数字。
使用递归(在C中):
#include<stdio.h> //fibonacci calculating function int fibo(int n) { if(n==1) return 0; else if(n==2) return 1; else return fibo(n-1) + fibo(n-2); } int main() { int n,res; printf("Enter n : "); scanf("%d",&n); res=fibo(n); printf("fibo(%d) = %d",n,res); return 0; }
输出:
Enter n : 5 fibo(5) = 3
斐波那契使用递归(如果n = 5)
如您所见,在我们上面的示例中,取n = 5,递归使用递归调用将问题分解为子问题。
仔细观察一下,请注意在这种情况下,fibo(3)
被计算了两次。
然后分解为两个递归调用fibo(1)和fibo(2)。
它们的值分别为0和1。
最后,我们得到了期望的输出,即fibo(5)= 3
。
应用DP(在C中):
#include<stdio.h> int fibo_series[100]; void set_zero() { int i; for (i = 1; i <= 100; i++) fibo_series[i] = 0; } //fibonacci calculating function int fibo(int n) { if (fibo_series[n] == 0) { if (n <= 1) fibo_series[n] = n; else fibo_series[n] = fibo(n - 1) + fibo(n - 2); } return fibo_series[n]; } int main () { int n,res; set_zero(); printf("Enter n : "); scanf("%d",&n); if(n>=100 || n<=0) printf("Entered number is out of range!"); else { res=fibo(n-1); printf("fibo(%d) = %d",n,res); } return 0; }
输出:
Enter n : 5 fibo(5) = 3
这次我们首先使用函数set_zero()初始化一个数组fibo_series [],该数组最多包含100个元素,其值为0。
一旦计算出此数组,该数组将进一步用于存储斐波那契数列的元素,
首先在fibo()函数内部,我们检查所需的元素是否已经计算并存储在数组中。
如果不是,则进行计算。
如果是,则将元素直接传递到函数调用的位置,这样可以确保同一函数(如我们先前看到的fibo(3))不会被调用两次。
因此,通过这种方式,我们获得了最佳解决方案。
注意:因为数组索引从零开始,所以我们在计算res时将(n-1)
传递给函数fibo()
。
鉴于我们正在考虑从索引1开始的系列元素。
出于相同的原因,我们使用了if-else语句来消除用户以" n> = 100"或者" n <= 0"输入n的情况。