算法设计课第五周作业

3. Tile a Grid With Dominoes

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.

image

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
3 
2 
3 
7
Sample Output
 1 5 
2 11 
3 781

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

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

动态规划算法的使用关键是起始状态和状态方程。 我们假设从左到右开始堆叠方块,使用二维数组dp记录,其中dp[i][j]表示叠到第i列的时候,状态为j的方法数。这个算法就是把矩形分成4*N个长宽都为1的正方块。dp[i][j]当矩阵宽为4,从上到下代表4位的二进制数字,当对应的数位为0时,表示那一列的那一个块是横放的,所以会影响到下一列。而且因为为2,最多只会影响到下一列。

(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)状态方程

说明第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];
(这条公式表示第i列当从上到下第三个格和第四格子需要横着放置俄罗斯方块时,第i-1列可能的情况有,i-1列第一第二行横放,或者i-1列全部的方块都不影响到下一列)一下的几条公式也类似

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;
}

猜你喜欢

转载自blog.csdn.net/weixin_38873581/article/details/86518283