遞歸與遞推:鑰匙計數之一

B - 鑰匙計數之一

 HDU - 1438 

一把鎖匙有N個槽,槽深爲1,2,3,4。每鎖匙至少有3個不同的深度且至少有1對相連的槽其深度之差爲3。求這樣的鎖匙的總數。

Input

本題無輸入

Output

對N>=2且N<=31,輸出滿足要求的鎖匙的總數。

Sample Output

N=2: 0
N=3: 8
N=4: 64
N=5: 360
..
..
..
..
..
..
..

N=31: ...

注:根據Pku Judge Online 1351 Number of Locks或 Xi'an 2002 改編,在那裏N<=16

【分析】

我做的時候沒有將遞歸/遞推的思想融進去,一直在想它排列組合的規律,而並沒有將其中每一項與其前一項聯繫起來,因爲我覺得這每一種情況增加一個“鑰匙槽”得到的下一種情況需要重新考慮,太離散,實際上遞推分情況考慮可以分析出來。

我們用a[i]來表示i個槽的滿足要求的鑰匙的總數。

則a[i]與a[i-1]之間有如下情況:

  • 若前i-1個槽已經符合要求,則最後一個槽可以是1,2,3,4:a[i] = a[i-1]*4;
  • 若前i-1個槽不符合要求,則分爲兩種情況:
  1. i-1個槽裏有相鄰且相差爲3的槽,則前i-1個槽裏一定只有兩種槽1和4,即1和4的全排列減去全爲4和全爲1的情況,那麼第i個槽一定爲3或2:a[i] = [2^(i-1)-2]*2; 
  2. i-1個槽裏沒有相鄰且相差爲3的槽,要使i個槽符合要求,則前i-2個槽一定沒有(1,4)或(4,1),且第i-1個槽一定是1或4,最後一個槽是4或1,前i-2個槽是所有情況4^(i-2)減去只有1和4的情況2^(i-2),到此爲止我們只剩前i-1個槽符合要求的鑰匙數沒有被剔除:a[i] = [4^(i-2)-2^(i-2)]*2-b[i-1];

【代碼】

#include<iostream>
#include<math.h>
#define ll long long
using namespace std;
int main()
{
    int i;
    ll temp,a[32],b[32];//b[i]記錄以1 4結尾的數
    a[2]=0;
    a[3]=8;
    b[2]=0;
    b[3]=4;
    printf("N=2: 0\nN=3: 8\n");
    for(i=4;i<=31;i++)
    {
        a[i]=a[i-1]*4;//n-1已經合法
        a[i]+=(ll)(2*(pow(2,i-1)-2));//n-1序列全爲1,4
        temp=((ll)pow(4,i-2)-(ll)pow(2,i-2))*2-b[i-1];//結尾爲(1,4)且合法
        a[i]+=temp;
        b[i]=a[i-1]*2+temp;//n個序列,結尾爲1,4且合法,加上n-1個序列且合法的一半(1或者4)
        printf("N=%d: %I64d\n",i,a[i]);
    }
    return 0;
}

 

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