Fibonacci数列 递归 杨辉三角 动态规划
生活随笔
收集整理的這篇文章主要介紹了
Fibonacci数列 递归 杨辉三角 动态规划
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
這篇帖子主要是介紹?遞歸?與 動態(tài)規(guī)劃 之間是如何轉(zhuǎn)換的,
什么是遞歸估計不用多說,那么什么是?動態(tài)規(guī)劃呢?
我理解的動態(tài)規(guī)劃就是:
能夠避免 直接 遞歸實現(xiàn) 中出現(xiàn)的重復運算的技術(shù)就是動態(tài)規(guī)劃。
這里有三個關(guān)鍵詞:"直接"、"遞歸實現(xiàn)"、"重復運算"
也許最簡單的, 也是眾所周知的動態(tài)規(guī)劃題目是?Fibonacci數(shù)列,?
如果你不知道,說明你的老師也不知道,而且我為你感到難過。
但是,遺憾的是,本文將 選取另一個也是眾所周知的動態(tài)規(guī)劃題目:?
二項式系數(shù) C(m, n)
它的遞推公式如下:
C(m, n) = C(m-1, n-1) + C(m-1, n), C(m, 0) = 1, C(m, m) = 1;
你或許會很驚訝,這是什么?我根本不熟悉嘛!
好吧,我想楊輝三角你應(yīng)該不陌生,是個c語言的書籍都會有這道題,
那么,你還記不記得楊輝三角 與 二項式系數(shù)有那么一點點的關(guān)系呢?
記不得,翻書吧!
首先,我(不是我們)給出 C(m, n)的?直接遞歸實現(xiàn)。
#include <stdio.h>
int C(int M, int N);
int main(void)
{
??? printf("%d\n", C(5, 2));
??? getchar();
??? return 0;
}
int C(int M, int N)
{
????
??? if (N == 0 || M == N)
??? {
????????return 1;
??? }
??? return C(M-1, N-1) + C(M-1, N);
}
輸出:10
那么, 這個實現(xiàn)直接嗎?
當然直接,公式就是這樣定義的啊。不是嗎?
然后, 可以肯定的是這個實現(xiàn)有 重復運算,
肯定有,要不然不會拿這道題作為例程解析。
怎么樣知道這個實現(xiàn)有 重復運算呢?
很簡單,把遞歸調(diào)用路徑打印出來看一眼就行了,僅僅是一眼。
在此之前,得確信你會 復制/粘帖 控制臺中的內(nèi)容,如果你還不會,
那么,請你百度一下吧。
我給函數(shù)多加一個參數(shù)用來記錄 遞歸調(diào)用深度?(這項技術(shù)已經(jīng)被我多次使用,不知你的技術(shù)敏感度怎么樣,有沒有留意過)?
然后,重新實現(xiàn)一下代碼。
#include <stdio.h>
int C(int M, int N, int depth);
int main(void)
{
??? printf("\nc(5, 2) = %d", C(5, 2, 0));
??? getchar();
??? return 0;
}
int C(int M, int N, int depth)
{
??? int i, ret;
??? for (i = 0; i < depth; i++)
??? {
????????printf(" ");
??? }
??? printf("C(%d, %d)\n", M, N);
??? if (N == 0 || M == N)
??? {
????????return 1;
??? }
??? return C(M-1, N-1, depth+1) + C(M-1, N, depth+1);
}?
輸出:
C(5, 2)
C(4, 1)
??C(3, 0)
??C(3, 1)
???C(2, 0)
???C(2, 1)
??? C(1, 0)
??? C(1, 1)
C(4, 2)
??C(3, 1)
???C(2, 0)
???C(2, 1)
??? C(1, 0)
??? C(1, 1)
??C(3, 2)
???C(2, 1)
??? C(1, 0)
??? C(1, 1)
???C(2, 2)
c(5, 2) = 10
很明顯的可以看出,C(1, 1)被多次運算過,當然不只是C(1, 1)了, 還有C(2, 1)呢?還有,...?
然后,怎么樣避免這個實現(xiàn)中的重復運算呢?
還記得先前有個帖子 "打家看看這個遞歸的 為什么結(jié)果要存起來 不能直接返回T 求N的階乘的遞歸都不要存結(jié)果" 嗎?
好吧,接下來咱采用相同的技術(shù):把結(jié)果保存起來。
#include <stdio.h>
#define M 5
#define N 2
int C(int m, int n, int depth);
int knownC[M+1][N+1] = {0};
int main(void)
{
??? printf("\nc(%d, %d) = %d\n", M, N, C(M, N, 0));
??? getchar();
??? return 0;
}
int C(int m, int n, int depth)
{
??? int i, ret;
??? for (i = 0; i < depth; i++)
??? {
????????printf(" ");
??? }
??? printf("C(%d, %d)\n", m, n);
??? if (knownC[m][n] != 0)
??? {
????????return knownC[m][n];
??? }
??? if (n == 0 || m == n)
??? {
????????ret = 1;
??? }
??? else
??? {
????????ret = C(m-1, n-1, depth+1) + C(m-1, n, depth+1);
??? }
??? return knownC[m][n] = ret;
}
輸出:
C(5, 2)
C(4, 1)
??C(3, 0)
??C(3, 1)
???C(2, 0)
???C(2, 1)
??? C(1, 0)
??? C(1, 1)
C(4, 2)
??C(3, 1)
??C(3, 2)
???C(2, 1)
???C(2, 2)
c(5, 2) = 10
這個就是 所謂的?"自頂向下動態(tài)規(guī)劃"?。
現(xiàn)在, 我們回到先前 所說的?"楊輝三角",
利用楊輝三角解 C(m, n) 。
#include <stdio.h>
#define M 5
#define N 2
int main(void)
{
????
??? int C[M+2][M+2] = {0, 1};
??? int i, j;
??? for (i = 1; i < M+2; i++)
??? {
????????for (j = 1; j <= i; j++)
????????{
????????????C[i][j] = C[i-1][j-1] + C[i-1][j];
????????}
??? }
??? printf("%d\n", C[M+1][N+1]);
??? return 0;
}
這個就是 所謂的?"自底向上動態(tài)規(guī)劃"?。
什么是遞歸估計不用多說,那么什么是?動態(tài)規(guī)劃呢?
我理解的動態(tài)規(guī)劃就是:
能夠避免 直接 遞歸實現(xiàn) 中出現(xiàn)的重復運算的技術(shù)就是動態(tài)規(guī)劃。
這里有三個關(guān)鍵詞:"直接"、"遞歸實現(xiàn)"、"重復運算"
也許最簡單的, 也是眾所周知的動態(tài)規(guī)劃題目是?Fibonacci數(shù)列,?
如果你不知道,說明你的老師也不知道,而且我為你感到難過。
但是,遺憾的是,本文將 選取另一個也是眾所周知的動態(tài)規(guī)劃題目:?
二項式系數(shù) C(m, n)
它的遞推公式如下:
C(m, n) = C(m-1, n-1) + C(m-1, n), C(m, 0) = 1, C(m, m) = 1;
你或許會很驚訝,這是什么?我根本不熟悉嘛!
好吧,我想楊輝三角你應(yīng)該不陌生,是個c語言的書籍都會有這道題,
那么,你還記不記得楊輝三角 與 二項式系數(shù)有那么一點點的關(guān)系呢?
記不得,翻書吧!
首先,我(不是我們)給出 C(m, n)的?直接遞歸實現(xiàn)。
#include <stdio.h>
int C(int M, int N);
int main(void)
{
??? printf("%d\n", C(5, 2));
??? getchar();
??? return 0;
}
int C(int M, int N)
{
????
??? if (N == 0 || M == N)
??? {
????????return 1;
??? }
??? return C(M-1, N-1) + C(M-1, N);
}
輸出:10
那么, 這個實現(xiàn)直接嗎?
當然直接,公式就是這樣定義的啊。不是嗎?
然后, 可以肯定的是這個實現(xiàn)有 重復運算,
肯定有,要不然不會拿這道題作為例程解析。
怎么樣知道這個實現(xiàn)有 重復運算呢?
很簡單,把遞歸調(diào)用路徑打印出來看一眼就行了,僅僅是一眼。
在此之前,得確信你會 復制/粘帖 控制臺中的內(nèi)容,如果你還不會,
那么,請你百度一下吧。
我給函數(shù)多加一個參數(shù)用來記錄 遞歸調(diào)用深度?(這項技術(shù)已經(jīng)被我多次使用,不知你的技術(shù)敏感度怎么樣,有沒有留意過)?
然后,重新實現(xiàn)一下代碼。
#include <stdio.h>
int C(int M, int N, int depth);
int main(void)
{
??? printf("\nc(5, 2) = %d", C(5, 2, 0));
??? getchar();
??? return 0;
}
int C(int M, int N, int depth)
{
??? int i, ret;
??? for (i = 0; i < depth; i++)
??? {
????????printf(" ");
??? }
??? printf("C(%d, %d)\n", M, N);
??? if (N == 0 || M == N)
??? {
????????return 1;
??? }
??? return C(M-1, N-1, depth+1) + C(M-1, N, depth+1);
}?
輸出:
C(5, 2)
C(4, 1)
??C(3, 0)
??C(3, 1)
???C(2, 0)
???C(2, 1)
??? C(1, 0)
??? C(1, 1)
C(4, 2)
??C(3, 1)
???C(2, 0)
???C(2, 1)
??? C(1, 0)
??? C(1, 1)
??C(3, 2)
???C(2, 1)
??? C(1, 0)
??? C(1, 1)
???C(2, 2)
c(5, 2) = 10
很明顯的可以看出,C(1, 1)被多次運算過,當然不只是C(1, 1)了, 還有C(2, 1)呢?還有,...?
然后,怎么樣避免這個實現(xiàn)中的重復運算呢?
還記得先前有個帖子 "打家看看這個遞歸的 為什么結(jié)果要存起來 不能直接返回T 求N的階乘的遞歸都不要存結(jié)果" 嗎?
好吧,接下來咱采用相同的技術(shù):把結(jié)果保存起來。
#include <stdio.h>
#define M 5
#define N 2
int C(int m, int n, int depth);
int knownC[M+1][N+1] = {0};
int main(void)
{
??? printf("\nc(%d, %d) = %d\n", M, N, C(M, N, 0));
??? getchar();
??? return 0;
}
int C(int m, int n, int depth)
{
??? int i, ret;
??? for (i = 0; i < depth; i++)
??? {
????????printf(" ");
??? }
??? printf("C(%d, %d)\n", m, n);
??? if (knownC[m][n] != 0)
??? {
????????return knownC[m][n];
??? }
??? if (n == 0 || m == n)
??? {
????????ret = 1;
??? }
??? else
??? {
????????ret = C(m-1, n-1, depth+1) + C(m-1, n, depth+1);
??? }
??? return knownC[m][n] = ret;
}
輸出:
C(5, 2)
C(4, 1)
??C(3, 0)
??C(3, 1)
???C(2, 0)
???C(2, 1)
??? C(1, 0)
??? C(1, 1)
C(4, 2)
??C(3, 1)
??C(3, 2)
???C(2, 1)
???C(2, 2)
c(5, 2) = 10
這個就是 所謂的?"自頂向下動態(tài)規(guī)劃"?。
現(xiàn)在, 我們回到先前 所說的?"楊輝三角",
利用楊輝三角解 C(m, n) 。
#include <stdio.h>
#define M 5
#define N 2
int main(void)
{
????
??? int C[M+2][M+2] = {0, 1};
??? int i, j;
??? for (i = 1; i < M+2; i++)
??? {
????????for (j = 1; j <= i; j++)
????????{
????????????C[i][j] = C[i-1][j-1] + C[i-1][j];
????????}
??? }
??? printf("%d\n", C[M+1][N+1]);
??? return 0;
}
這個就是 所謂的?"自底向上動態(tài)規(guī)劃"?。
總結(jié)
以上是生活随笔為你收集整理的Fibonacci数列 递归 杨辉三角 动态规划的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 递归与递推的区别
- 下一篇: UVa 10359 - Tiling