计算网格的多米诺覆盖数

Posted

技术标签:

【中文标题】计算网格的多米诺覆盖数【英文标题】:Calculate number of domino-coverings for a grid 【发布时间】:2013-09-03 02:02:40 【问题描述】:

我正在尝试在SPOJ GNY07H 上解决这个问题: 问题是:

我们希望平铺一个 4 个单位高、N 个单位长的网格,其中包含 2 个单位乘一个单位的矩形(多米诺骨牌)(在任一方向上)。

编写一个程序,将网格的宽度 W 作为输入,并输出平铺 4×W 网格的不同方法的数量。

输入: 2 3 7

输出: 5 11 781

我知道这是一个位掩码动态编程问题。 但是,我的方法没有得到正确的输出。谁能指出我的方法中的错误。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <climits>

using namespace std;

int dp[16][4][60];

int solve(int mask, int d, int t)

    if(t > 4)   return 0;
    if(d == 0)  return mask == 0;
    if(t == 4)  return solve(mask, d-1, 0);
    int &ret = dp[mask][t][d];
    if(ret != -1)
        return ret;
    ret = 0;
    ret += solve(mask|(1<<t), d, t+1) + solve(mask, d, t+2);
    return ret;


int main()

    int i, j, k, l, n, w;

    scanf("%d", &n);

    while(n--)
    
        memset(dp, -1, sizeof(dp));
        scanf("%d", &w);
        int ans = solve(0, w, 0);
        printf("%d\n", ans);
    
    return 0;

该方法的工作原理如下:

我一行一行地工作。在每一行,对于一列,我尝试先水平和垂直放置瓷砖。 mask 属性告诉行+1 中哪些列已经被填充。因此,当 tile 水平放置在行中时,mask = mask | (1 t)) 用于第 1 行,否则保持不变。我以这种方式计算可能性的总数。递归的停止条件是当行(在程序中为 d)时掩码为 0,即行变为 0。当所有此级别的列已填满。

【问题讨论】:

你能花几分钟解释一下这应该做什么吗?链接不会永远存在。 【参考方案1】:

我没有花时间完全理解这个问题,但只是看一下代码,这看起来像是一个没有计算的缓存机制。在主循环的每次迭代中,您将缓存 dp 设置为全 -1,但您没有在其他任何地方将其内容设置为其他任何值。然后在solve() 中,有几个返回 0 的特殊情况,然后是返回几个递归调用之和的主要情况;但是这些递归调用也无法合法地返回零以外的任何值。

solve() 似乎缺少两件事:

    一种极限情况,对于 d、t 和 mask 的某些值,非递归计算数值;和 在某些时候,计算值应存储在dp

此外,我认为缓存dp 可能应该在main() 中的循环外部清除,尽管我不是100% 确定这一点。

【讨论】:

抱歉,缓存值正在 solve() 函数内更新。 int &ret = dp[mask][t][d] 可以解决问题。 呃,你是对的,对不起。事实上,“return mask == 0”也将返回非零值。这就是我早上喝咖啡前回答问题所得到的。

以上是关于计算网格的多米诺覆盖数的主要内容,如果未能解决你的问题,请参考以下文章

计算二维数组上的路径数(网格旅行者)

Codeforces Round #742 (Div. 2) 题解

有啥方法可以为 CuPy 计算设置线程数、块数和网格数?如何?

基于geohash6编码实现相邻4916网格合并

AOJ 589.多米诺

P3166 [CQOI2014]数三角形