題目:樓梯有n階臺階,上樓可以一步上1階,2階,3階,編程序計算共有多少種不同的走法?對於這樣一個問題,
思路:設n階臺階的走法數爲f(n)。如果只有1個臺階,走法有1種(一步上1個臺階),即f(1)=1;如果有2個臺階,走法有2種(一種是上1階,再上1階,另一種是一步上2階),即f(2)=2;如果有3個臺階,走法有4種(一種每次1階,共一種;另一種是2+1,共兩種;第三種是3,共1種),即f(3)=4;
當有n個臺階(n>3)時,我們縮小問題規模,可以這樣想:最後是一步上1個臺階的話,之前上了n-1個臺階,走法爲f(n-1)種,而最後是一步上2個臺階的話,之前上了n-2個臺階,走法爲f(n-2)種,故而f(n)=f(n-1)+f(n-2)。列出的遞歸方程爲:f(1)=1;f(2)=2;
f(3)=4;
if(n==1)
return 1;
else if(n==2)
return 2;
else if(n==3)
return 4;
else
return f(n-1)+f(n-2)+f(n-3),n>3
最後一步可能是從第n-1階往上走1階、從n-2階往上走2階,或從第n-3階往上走3階。因此,抵達最後一階的走法,其實就是抵達這最後三階的方式的總和。
解決方法1:按照遞歸的思想;但運算時間很長
int countWays (int n) {if (n<0) return 0; if (n==0) return 1; else { return countWays(n-1)+countWays(n-2)+countWays(n-3); } }
解決方法2:採用動態規劃的思想 優化,
當一個問題可以分解成若干重複的子問題時,運用動態規劃的思想:
只需要將子問題求解一次,以後再遇到,直接調用,所以我們新建一個數組用於存儲子問題的結果:
將數組元素初始爲零,若爲新的子問題,我們求解,並把結果賦給對應的數組元素;這樣當我們再次遇到相同的子問題,就可以直接調用了。
int countWaysDP(int n, dp[])
{
if (n<0)
return 0;
if (n==0)
return dp[n];
if (dp[n]>0)
return dp[n]; //如果大於0 說明這個子問題已經計算過,直接調用數組
else
{ dp[n]=countWays[n-1,dp]+countWays[n-2,dp]+countWays[n-3,dp]; //否則 還需計算該數組
return dp[n];
}
}
#include<iostream>
using namespace std;
const int MAX=1000;
int countWays(int n)
{if (n<0)
return 0;
if (n==0)
return 1;
else
{
return countWays(n-1)+countWays(n-2)+countWays(n-3);
}
}
int countWaysDP(int n, int dp[])
{
if (n<0)
return 0;
if (n==0)
return 1;
if (dp[n]>0)
return dp[n]; //如果大於0 說明這個子問題已經計算過,直接調用數組
else
{ dp[n]=countWaysDP(n-1,dp)+countWaysDP(n-2,dp)+countWaysDP(n-3,dp); //否則 還需計算該數組
return dp[n];
}
}
int main()
{
int m[MAX]={0};
// int m[MAX];
for(int i=1;i<10;i++)
cout<<countWaysDP(i,m)<<endl;
}