hdu2041超级楼梯 斐波那契数/dp/搜索

题目链接

当前在1,可以走一级到2,或者走两级到3,到2的时候可以走一级也可以走两级,以此类推
1
2 3
3 4 4 5
4 5 5 6 5 6 6 7
5 6 6 7 6 7 7 8 6 7 7 8 7 8 8 9

可以发现,每季楼梯都可以通过上一级楼梯+1走到当前楼梯,后者前面第二级+2走到当前楼梯,因此,第n级的状态是有上一级和上两级的状态转移而来,得到Fn=Fn-1+Fn-2,可以用dp做这道题(dp的话前面这个公式就是状态转移方程),也可以发现这是斐波那契数的规律,可以用矩阵乘法写斐波那契过这题(虽然对这道题没有必要用矩阵乘法,但是如果题目范围大一点的话就有必要了,因此这里也加个矩阵乘法的解法),当然,因为范围n<=40,当然,对于方案数也可以选择用wang搜索的方法,但是这题测了一下,用暴搜一到n>=38的话就会t掉,38以下的数据点都能过

直接用总结出来的公式暴力打表输出答案:

#include<iostream>
#include<cstring>
#include<algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N=50;
ll F[N];

void Init()
{
    F[1]=1,F[2]=2;
    for(int i=3;i<N;i++){
        F[i]=F[i-1]+F[i-2];
    }
}

int main()
{
    Init();
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d", &n);
        printf("%lld\n",F[n-1]);
    }
    return 0;
}

矩阵乘法解斐波那契数ac代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N=2;
ll A[N][N],F[N];

void matrix1(ll a[N][N],ll b[N])
{
    ll t[N]={0};
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            t[i]=(t[i]+a[i][j]*b[j]);
        }
    }
    for(int i=0;i<N;i++)b[i]=t[i];
}

void matrix2(ll a[N][N],ll b[N][N])
{
    ll t[N][N]={0};
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            for(int k=0;k<N;k++){
                t[i][j]=(t[i][j]+a[i][k]*b[k][j]);
            }
        }
    }
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            a[i][j]=t[i][j];
        }
    }
}

void mat_pow(ll n)
{
    while(n){
        if(n&1)matrix1(A,F);
        matrix2(A,A);
        n>>=1;
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d", &n);
        for(int i=0;i<N;i++){
            F[i]=0;
            for(int j=0;j<N;j++)A[i][j]=0;
        }
        A[0][0]=A[0][1]=A[1][0]=1,F[0]=1;
        mat_pow(n);
        printf("%lld\n",F[1]);
    }
    return 0;
}

直接暴搜会t掉,提供一下暴搜代码(t掉部分用打表写一下答案就不会t了,对于数据范围小于38的题可以用暴搜过)

#include<iostream>
#include<cstring>
#include<algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

int n;
ll res;
const int N=50;
bool vis[N];

void DFS(int u)
{
    if(u>=n){
        if(u==n)res++;
        return;
    }
    if(!vis[u]){
        vis[u]=true;
        DFS(u+1);
        DFS(u+2);
        vis[u]=false;
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d", &n);
        res=0;
        DFS(1);
        if(n==1)res=0;
        printf("%lld\n",res);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值