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

 

 

你可能感兴趣的:(2015 UESTC Training for Dynamic Programming E - 菲波拉契数制(01背包))