zoukankan      html  css  js  c++  java
  • HDU

    n how many ways can you tile a 3xn rectangle with 2x1 dominoes? Here is a sample tiling of a 3x12 rectangle.
    在这里插入图片描述
    Input
    Input consists of several test cases followed by a line containing -1. Each test case is a line containing an integer 0 ≤ n ≤ 30.
    Output
    For each test case, output one integer number giving the number of possible tilings.
    Sample Input
    2
    8
    12
    -1
    Sample Output
    3
    153
    2131

    这道题的前身是若干个2×1的骨牌填满2×n。设当前填充长度为i,那么他只可能有下面两种情况:

    在这里插入图片描述
    或者
    在这里插入图片描述
    因此 f[i] = f[i-1] + f[i-2] ;

    那么看 若干个2×1的骨牌填满3×n的情况,设当前填充长度为i,如果i为奇数必定无法填满(可以动手画);如果i为偶数,那么i-2到i(长度为2的填法)有如下三种:

    在这里插入图片描述
    则 f[i]+=f[i-2]*3;( f[i]初始为0 )

    上面是把 i 切割为 i - 2 和 2 的情况,那切割为 i - 4 和 4 呢?
    便是这种情况 和 他的颠倒过来的情况。(共2种)在这里插入图片描述
    也许会产生疑问???
    为什么没有下图的情况。

    在这里插入图片描述
    因为类似与之前的填充长度为二的情况我们已经考虑了
    即 f[i] += f[i-2]* 3 => f[i-2] += f[i-4] * 3;
    当为填充i-2的时候就已经算了三种,i 的时候又算三种,根据组合计数已经把类似于上图这种情况算进去了。
    所以
    f[i] += f[i-4] * 2;
    同理

    在这里插入图片描述
    (该图片为百度搜得,若有雷同,还望口下留德 Orz )
    最终
    f[n]= 3 * f[n-2] + 2 * f[n-4] + 2 * f[n-6] +…+ 2 * f [0];
    由上式得出:
    f[n-2] =3 * f[n-4] + 2 * f[n-6] + 2 * f[n-8]+…+ 2 * f[0];

    化简得:f[n]=4*f[n-2]-f[n-4] ;

    AC代码

    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    using namespace std;
    typedef long long LL;
    const int N=2e5+5;
    int n;
    LL f[35];
    int main()
    {
        f[0]=1; f[1]=0; f[2]=3;
        for(int i=3;i<=30;i++)
        {
            if(i&1) f[i]=0;
            else
                f[i]=f[i-2]*4-f[i-4];
        }
        while(scanf("%d",&n)==1&&n!=-1)
        {
            printf("%lld
    ",f[n] );
        }
        return 0;
    }

    另一种思路
    f[i][0]=f[i-2][0]+f[i-1][1]+f[i-2][2];
    f[i][1]=f[i-1][2];
    f[i][2]=f[i][0]+f[i-1][1];
    AC代码

    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    using namespace std;
    typedef long long LL;
    const int N=2e5+5;
    int n,m;
    LL f[35][3];
    int main()
    {
        f[0][0]=f[0][2]=1;
        for(int i=1;i<=30;i++)
        {
            if(i&1) f[i][0]=0;
            else
                f[i][0]=f[i-1][1]+f[i-2][2]+f[i-2][0];
            f[i][1]=f[i-1][2];
            f[i][2]=f[i][0]+f[i-1][1];
        }
        while(scanf("%d",&n)==1&&n!=-1)
        {
            printf("%lld
    ",f[n][0] );
        }
        return 0;
    }

    这种思路有点难理解,详见另一个大佬博客:
    点此跳转

  • 相关阅读:
    VS.NET 生成后事件
    SysVinit
    技巧:Linux I/O重定向的一些小技巧
    Ofono/Phonesim 安装和启动
    Memory Hierarchy
    Linux 技巧:让进程在后台可靠运行的几种方法 用 cron 和 at 调度作业 使用 screen 管理你的远程会话
    M. Tim Jones
    How do I install Oracle Java JDK 7?
    详谈 UNIX 环境进程异常退出
    Linux 内核剖析
  • 原文地址:https://www.cnblogs.com/DeepJay/p/12025221.html
Copyright © 2011-2022 走看看