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
原文地址:https://www.cnblogs.com/chenyg32/p/3130195.html