• 8223. Tiling a Grid With Dominoes


    Description

    We wish to tile a grid 4 units high and N units long with rectangles (dominoes) 2 units by one unit (in either orientation). For example, the figure shows the five different ways that a grid 4 units high and 2 units wide may be tiled.

     

    Write a program that takes as input the width, W, of the grid and outputs the number of different ways to tile a 4-by-W <tex2html_verbatim_mark>grid.

    Input

    The first line of input contains a single integer N(1<=N<=1000) which is the number of datasets that follow.

    Each dataset contains a single decimal integer, the width, W, of the grid for this problem instance.

    Output
    For each problem instance, there is one line of output: The problem instance number as a decimal integer (start counting at one), a single space and the number of tilings of a 4-by-W grid. The values of W will be chosen so the count will fit in a 32-bit integer.
    Sample Input
     Copy sample input to clipboard
    3 
    2 
    3 
    7
    
    Sample Output
    1 5 
    2 11 
    3 781


    dp[i]表示宽度为i的排列种数。

    我们可以这样分解dp[i]

    i列依次分解为2部分,依次分解为 (i-1)+1列 (i-2)+2列 …… 1+(i-1)列

    那么dp[i] = dp[i-1]*dp[1] + dp[i-2]*dp[2] + ……+dp[1][i-1] -R

    R是重复的个数,事实上我们不必算出R,只要在计算dp[i-j]*dp[j]的时候去除掉与前面相同情况的个数即可。

    首先,dp[0] = dp[1] = 1, dp[2] = 5.

    少一列,最后一列的2个只能都是竖的对不对,所以是左边部分是dp[i-1],右边部分是dp[1]。少两列,左边部分是dp[i-2],右边部分是dp[2]-1=4

    如图,为了防止跟少1列的情况重复,所以倒数第二列不能2个竖的,剩下的几种可能画个图就明白。

     

    少j列,依然用这种思路,为了保证不跟前面的情况重复,我们倒数第j列必然不能是2个竖的。所以剩下4种可能,画图填充,就知道有几种可能。

    例如,少3列的时候,只有2种情况,所以dp[i-3]*2

    画着画着就知道:≥ 3

    少奇数列的时候(也就是j为奇数的时候),总数为dp[i-j]*2

    少偶数列的时候(也就是j为偶数的时候),总数为dp[i-j]*3

     

    所以状态转移方程就来啦:

    dp[i]=dp[i-1]+4*dp[i-2]+2*(dp[i-3]+dp[i-5]...)+3*(dp[i-4]+dp[i-6]...)

     

    #include <cstdlib>
    #include <iostream>
    using namespace std;
    #define Max 1002
    
    int dp[Max];
    
    void init()
    {
        dp[0] = 1;
        dp[1] = 1;
        dp[2] = 5;
        
        for (int i = 3; i <= Max; i++)
        {
            dp[i] = dp[i-1] + 4*dp[i-2];
            
            for(int j = 3; j <= i; j++)
                if(j%2)
                    dp[i] += 2*dp[i-j];
                else
                    dp[i] += 3*dp[i-j];
        }
    }
    
    int main()
    {    
        init();
        
        int m, n, cases = 1;
        
        cin >> m;
        
        while (m--)
        {
           cin >> n;
           
           cout << cases++ <<" "<< dp[n] <<endl;
        }
    }
    View Code
  • 相关阅读:
    ArrayList集合封装 类 并通过方法调用
    ArrayList集合的基本操作
    方法的重复定义和重载
    方法间值的传递,二维数组的定义和遍历
    赋值运算,逻辑运算符,引用数据类型
    Javase;jdk的安装调试;基础语法和变量以及基础数据类型
    E-R画图规则和数据库设计的三大范式
    sql多表查询和子查询
    sql约束的使用
    sql表操作的基础语法
  • 原文地址:https://www.cnblogs.com/chenyg32/p/3130195.html
Copyright © 2020-2023  润新知