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(i1)+F(i2)(i>=3)

给定任意一个数,我们可以把它表示成若干互不相同的菲波拉契数之和。比如13有三种表示法

13=13

13=5+8

13=2+3+8

现在给你一个数n,请输出把它表示成若干互不相同的菲波拉契数之和有多少种表示法。

Input

第一样一个数T,表示数据组数,之后T行,每行一个数n

T105

1n105

Output

输出T行,每行一个数,即n有多少种表示法。

Sample input and output

Sample InputSample 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 }

 

 
posted @ 2015-05-14 19:55  BYYB_0506  阅读(319)  评论(0编辑  收藏  举报