2015 UESTC Training for Dynamic Programming E - 菲波拉契数制(01背包)
E - 菲波拉契数制
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
我们定义如下数列为菲波拉契数列:
F(1)=1
F(2)=2
F(i)=F(i−1)+F(i−2)(i>=3)
给定任意一个数,我们可以把它表示成若干互不相同的菲波拉契数之和。比如13有三种表示法
13=13
13=5+8
13=2+3+8
现在给你一个数n,请输出把它表示成若干互不相同的菲波拉契数之和有多少种表示法。
Input
第一样一个数T,表示数据组数,之后T行,每行一个数n。
T≤105
1≤n≤105
Output
输出T行,每行一个数,即n有多少种表示法。
Sample input and output
Sample Input | Sample Output |
---|---|
6 1 2 3 4 5 13 |
1 1 2 1 2 3 |
解题思路:
上来后由于100000内的斐波那契数只有24个,所以我们只要打一个表把100000内的斐波那契数都筛选出来就OK了,然后,我们就把这个问题当做一个背包来做就好了。对于这24个数讨论是否放入背包。
状态:dp[j]表示从这24个数字中选出来不互相通的几个相加后的得到的结果是j的方法总数。
状态转移方程:dp[j] += dp[j-a[i]]; i:1->24,j:100000->0.
边界条件dp[0] = 1;
代码:
1 # include<cstdio> 2 # include<iostream> 3 # include<cstring> 4 5 using namespace std; 6 7 # define MAX 55 8 9 int n; 10 int a[MAX]; 11 int dp[100000+4]; 12 13 void init() 14 { 15 a[1] = 1; 16 a[2] = 2; 17 for ( int i = 3;i <= 24;i++ ) 18 { 19 a[i] = a[i-1]+a[i-2]; 20 } 21 22 dp[0] = 1; 23 for ( int i = 1;i <= 24 ;i++ ) 24 { 25 for ( int j = 100000;j >= a[i];j-- ) 26 { 27 dp[j]+=dp[j-a[i]]; 28 } 29 } 30 31 } 32 33 int main(void) 34 { 35 init(); 36 int t;scanf("%d",&t); 37 while ( t-- ) 38 { 39 scanf("%d",&n); 40 printf("%d\n",dp[n]); 41 42 } 43 44 return 0; 45 }