某個遞歸題引發的思考

題目大意

給定一排長度爲N(0<N<=50)的方格,向裏面填入a,b,c三個數。要求任何相鄰的方格數字不能相同,且首尾兩格也不能相同。問:N個格子有幾種填數方法

方法一(玄學大法)

首先進行暴力循環求結果得:
1 : 3
2 : 6
3 : 6
4 : 18
5 : 30
6 : 66
7 : 126

考慮到每一個數字開頭都一樣這裏除以三發現:

1 : 1
2 : 2
3 : 2
4 : 6
5 : 10
6 : 22
7 : 42

發現當n>3時有規律 f(n) = f(n-1) + f(n-2)*2

提交後發現AC了
發現AC了
AC了
???

這樣對學習遞歸沒有好處,我們再看看常規方法

方法二(普通な方法)

首先當只有一個格子的時候不需要顧忌規則,顯然有三種方法
當有兩個格子的時候顯然有六種方法
當有三個格子的時候通過排列發現也有六種方法

我們來思考一下有四個格子會怎麼樣
我們先列舉當N=3的一種狀態: 012
如果要是加一個格子去填數字的話是不是隻能填1呢?由於規則
但是讓你去列舉的話難道就只能列出這一種嗎?0101,0102他不行嗎?
但是爲什麼光從N=3裏列不出來呢?
因爲規則!!!
所以我們需要從N=2去考慮一下。
我們看看N=2時的一種狀態:01
給他加兩個格子讓他填數字的話可以怎麼填呢?
上過高中數學的應該都懂吧?
第三個位置可以填 0,2,當填0的時候第四個位置可以填1或2,當填2的時候只能再填一個1
一共三種填法。但是有一種卻是與N=3時的填法重複了我們需要去掉一個
即得出結果 f(4) = f(3) + (3-1)f(2) 有人可能會疑惑:爲什麼要去除從狀態N=2種得出來得一種而不是從狀態N=3的呢?

假設我們去掉了從狀態N=3來的那麼結果變成了f(4) = 3f(2),歸納總結得
f(n) = 3*f(n-2) 你會發現只滿足了上述這一種情況,故不正確。

所以你會發現結果還是f(n) = f(n-1) + f(n-2)*2

不過這是一次運用遞歸思想而得出得結論,和那種瞎猜不一樣

上代碼:

#include <cstdio>
#include <cstring>
long long int ans[52];
int n;
/*
1 : 3       
2 : 6       
3 : 6
4 : 18
5 : 30
6 : 66
7 : 126
*/
int main()
{
    int i;
    ans[1] = 3;
    ans[2] = 6;
    ans[3] = 6;
    ans[4] = 18;//18
    for(i=5;i<=50;i++)
    {
        ans[i] = ans[i-1] + 2 * ans[i-2];
    }
    while(scanf("%d",&n) != EOF)
        printf("%lld\n",ans[n]*3);
    //for(i=1;i<=50;i++)printf("%d : %lld\n",i,ans[i]);
    return 0;
}

順便說一下:任何遞歸能得出的結果用迭代的方式同樣能得出來。目前你可以把迭代當作for循環

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章