<OJ_Sicily>Tiling a Grid With Dominoes

40 篇文章 0 订阅

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 grid.

Input

The first line of input contains a single integer N , MATH $(1 \le N \le 1000)$ (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.

题目解释:使用大小为2*1的木块去组合成宽为W,高为4的矩形,求解方法数。

解题思路:使用动态规划实现求解。

这道题其实很像我们平时玩的俄罗斯方块,我们的目的就是无缝填满。动态规划算法的使用关键是起始状态和状态方程。 我们假设从左到右开始堆叠方块,使用二维数组dp记录,其中dp[i][j]表示叠到第i列的时候,状态为j的方法数。

(1)初始条件。不妨设想一下,我们目前为空,我们开始堆叠第1列,那么有多少种叠法呢?全部情况如下图所示:


所以这是一个初始状态 dp[1][0] = dp[1][3] = dp[1][6] = dp[1][12] = dp[1][15] = 1; 其中初始状态只能为0,3,6,12,15。其中0表示没有被覆盖,1表示已经被覆盖

(2)状态方程

相比于初始状态,在后面不断地填充过程中还会出现状态9的情况,对于第i列(i>1)的全部状态如下图所示:


下面分析其中一种状态转换,其他可以同理推出。下面分析第i列出现状态15(1111)的情况。


说明第i-1列的状态为0,3,6,12,15的时候都能实现第i列状态为15(1111)

因此有: dp[i][15] = dp[i-1][0] + dp[i-1][3] + dp[i-1][6] + dp[i-1][12] + dp[i-1][15];

同理:

dp[i][12] = dp[i-1][3] + dp[i-1][15];

dp[i][9] = dp[i-1][6];

dp[i][6] = dp[i-1][9] + dp[i-1][15];

dp[i][3] = dp[i-1][15] + dp[i-1][12];

dp[i][0] = dp[i-1][15];

(3)最终要求的是宽度为W的方法数,也就是dp[w][15]的值

#include <iostream>
#include <string.h>
using namespace std;
int caseNum, w;
int dp[1005][16];     // 状态矩阵
int main(int argc, const char * argv[]) {
    // insert code here...
    cin >> caseNum;
    int curIndex = 1;
    while (curIndex <= caseNum) {
        cin >> w;
        if(w == 0) {
            cout << curIndex++ << " "<< 0 << endl;
            continue;
        }
        memset(dp, 0, sizeof(dp));
        dp[1][0] = dp[1][3] = dp[1][6] = dp[1][12] = dp[1][15] = 1;
        for (int i = 2; i <= w; i++) {
            dp[i][15] = dp[i-1][0] + dp[i-1][3] + dp[i-1][6] + dp[i-1][12] + dp[i-1][15];
            dp[i][12] = dp[i-1][3] + dp[i-1][15];
            dp[i][9] = dp[i-1][6];
            dp[i][6] = dp[i-1][9] + dp[i-1][15];
            dp[i][3] = dp[i-1][15] + dp[i-1][12];
            dp[i][0] = dp[i-1][15];
        }
        cout << curIndex++ << " " << dp[w][15] << endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值