稳定/免分割线多米诺骨牌的棋盘覆盖问题

前言

多米诺骨牌的棋盘覆盖问题是一类经典的数学/算法问题。本文讨论添加了免分割线约束条件的多米诺骨牌覆盖问题。

问题描述

多米诺骨牌是 2 × 1 或 1 × 2 的矩形。
考虑用多米诺骨牌覆盖 m × n棋盘,如果无法通过一条不穿过任何骨牌内部的直线,将一种覆盖方案分割成两个部分,那么这种覆盖方案被称为是稳定的。


(a), (b) 是稳定的,(c), (d) 是不稳定的
(a), (b) 是稳定的,(c), (d) 是不稳定的

存在性问题:对于 m × n 的棋盘,是否存在稳定的多米诺骨牌的覆盖方案?
计数问题:对于 m × n 的棋盘,有多少种稳定的多米诺骨牌的覆盖方案?


输入输出

Input

多组测试数据。每组测试数据的第一行包含两个整数 m 和 n (1 ≤ m, n ≤ 16) 表示矩形的大小。

Output

对于每组测试数据,输出一行一个整数表示对应稳定多米诺骨牌覆盖的方案数。
答案可能很大,输出模 1000000007 (10^9 + 7) 的结果。

Input示例

2 2
5 6
8 7
15 16

Output示例

0
6
13514
856463275

问题链接

存在性问题

存在性问题在这文章里已经解释得很清楚。在这里只是给出该文章的一些思路和线索。
首先m,n不能都为奇数。因为当两者都为奇数时,棋盘格子总数m × n 为奇数,而骨牌覆盖格子数为偶数,所以不存在覆盖方案。
下面进一步讨论m,n的可能取值情况,并假设m,n不同时为奇数。根据对称性,不妨假设m≤ n。我们自小到大讨论m的可能取值。

  1. m=1或m=2。显然只有平凡解 (m,n) = (1, 2) 。
  2. m=3或m=4。自左往右分析可能的放置方式。根据免分割线条件,只能放置成几种固定模式,且这几种模式都不能构成齐整的右边缘。
  3. (m,n) = (5,6), (6,8) 时可以构造出解。我们将这两个解看作(m,n) = (奇数 ,偶数), (偶数,偶数)的基础解。基于这两个基础解,我们能通过扩展方法构造出其他(奇数 ,偶数), (偶数,偶数)情况下的解。扩展方法是将覆盖最后一列/行的骨牌平移两个格子,并在平移产生的空隙中插入横/竖放的骨牌。
  4. (m,n) = (6,6) 时无解。无解的证明方法是反证法+“算两次”。假设结论成立。覆盖骨牌数是18。注意到,穿过每条分割线的骨牌数必须是偶数,否则由该分割线分割的两部分中的任意份都只有奇数格子,无法被覆盖,所以每条分割线至少穿过2个骨牌。另外分割线共有10条,因此总骨牌数至少为20个。矛盾!

综上,得出除平凡解外的解的充分必要条件:

  1. M 和 N 至少有一个是偶数。
  2. M 和 N 都大于 4 。
  3. M 和 N 不同时等于 6 。

计数问题

棋盘类的计数问题很容易想到用动态规划求解。但是这里存在一个较大的问题,分割线在水平方向和竖直方向上都不能有分割线,这个性质使得我们很难将覆盖问题切分为更小的子问题求解,也即是说很难直接应用动态规划。对于这一类含有全局性质的计数问题,可以考虑用容斥原理计算。将求解具有稳定性质的覆盖问题转化成求解无稳定性质的覆盖问题。

[补集交形式的容斥原理](https://zh.wikipedia.org/wiki/%E6%8E%92%E5%AE%B9%E5%8E%9F%E7%90%86)

不考虑分割线覆盖方案称为完美覆盖。完美覆盖的计数问题可以使用动态规划求解。

假设已经求出了 i × j 棋盘的完美覆盖数(Pij)。我们对列运用容斥原理。容斥原理中的Ai表示被i条竖直分割线分割的无横向分割线的覆盖方案;S表示所有无横向分割线的覆盖方案。为了叙述方便,我们称若干个Ai的交称为竖直分割方案。根据容斥原理,我们需要计算每种竖直分割方案下的无横向分割线的覆盖数(R)。我们使用按行(r)递推的方式求解R, 其中Ri表示 i × n棋盘的无横向分割线的覆盖数, 所以R=Rm。为了求解Ri,我们定义一个竖直分割方案下 i × n棋盘的完美覆盖数为SPi,SPi的值等于被竖直分割线切分的所有小棋盘完美覆盖数的乘积。假设竖直方案将棋盘切分为3个小棋盘( i × a, i × b, i × c),其中a+b+c=n。则SPi = Pia × Pib × Pic. 根据上述定义,Ri的递推公式如下:

  1. r = 1, R1 = SP1
  2. r = k, Rk = SPk - R1 × SPk-1 - R2 × SPk-2 - … - Rk-1 × SP1

递推原理是将SPk按照位置最高的横向分割线(rc)将覆盖方案分为不相交的k类。每条rc将棋盘分为上下两部分,上部分无横向分割线,下部分允许有横向分割线。假设上部分有l行,则该类的覆盖方案数为Rl × SPk-l

代码如下(含完美覆盖):

#include<iostream>
using namespace std;

#define LL long long
#define N 16
LL P[N + 1][N + 1];
LL pc[N + 1][N + 1][1 << N];
LL mod = 1000000007;

pair<LL, LL> p(LL x, LL y, LL i, LL col) {
    if (y > i) return make_pair(x, y - i);
    else return make_pair(x - 1, col);
}

void initP(LL col) {
    LL stateNum = 1 << col;
    for (LL j = 1; j <= col; j++) {
        pc[0][j][stateNum - 1] = 1;
    }
    for (LL i = 1; i <= N; i++) {
        for (LL j = 1; j <= col; j++) {
            LL b = 1 << (j - 1);
            for (LL k = 0; k < stateNum; k++) {
                auto pre = p(i, j, 1, col);
                pc[i][j][k] = pc[pre.first][pre.second][k ^ b];
                LL b2 = 3 << (j - 2);
                if (j > 1 && (b2 & k) == b2) {
                    auto pre1 = p(i, j, 2, col);
                    pc[i][j][k] = (pc[i][j][k] + pc[pre1.first][pre1.second][k]) % mod;
                }
            }
        }
        P[i][col] = pc[i][col][stateNum - 1];
    }
}

void initP() {
    for (LL j = 1; j <= N; j++) {
        initP(j);
    }
}

void getSection(LL state, LL sec[], LL &l, LL y) {
    LL start = 0;
    for (LL j = 1; j < y; j++) {
        if (state & (1 << (j - 1))) {
            sec[l++] = j - start;
            start = j;
        }
    }
    sec[l++] = y - start;
}

int main() {
    initP();
    LL x, y;
    while (cin >> x >> y) {
        LL stateNum = 1 << (y - 1);
        LL ans = 0;
        for (LL i = 0; i < stateNum; i++) {
            LL section[N];
            LL sectionLength = 0;
            LL R[N + 1];
            LL SP[N + 1];
            getSection(i, section, sectionLength, y);
            for (LL r = 1; r <= x; r++) {
                SP[r] = 1;
                for (LL j = 0; j < sectionLength; j++)
                    SP[r] = SP[r] * P[r][section[j]] % mod;
            }
            for (LL r = 1; r <= x; r++) {
                R[r] = SP[r];
                for (LL l = 1; l < r; l++) {
                    R[r] = (R[r] - R[l] * SP[r - l]) % mod;
                }
            }
            if (sectionLength % 2 == 0)
                ans = (ans - R[x]) % mod;
            else
                ans = (ans + R[x]) % mod;
        }
        cout << (ans + mod) % mod << endl;
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,924评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,902评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,716评论 0 239
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,783评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,166评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,510评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,784评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,476评论 0 196
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,196评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,459评论 2 243
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,978评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,321评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,964评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,046评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,803评论 0 193
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,530评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,420评论 2 265

推荐阅读更多精彩内容

  • 参考blog 棋盘覆盖问题 问题描述 在一个2^k * 2^k个方格组成的棋盘中,有一个方格与其它的不同,若使用以...
    chenhh6701阅读 3,188评论 0 4
  • 分治策略 本文包括分治的基本概念二分查找快速排序归并排序找出伪币棋盘覆盖最大子数组 源码链接:https://gi...
    廖少少阅读 1,742评论 0 7
  • 宽容的早晨仿佛有治愈的魔力,无论在黑暗的 夜睡的多久多沉,当菀红的朝霞打到一片片劲绿的 树林,泛起橘红的...
    心的字阅读 214评论 0 0
  • 【坤卦易传原文·文言传(三)】 文言曰:直(1)其正也,方其义(2)也。君子敬以直内,义以方外(3),敬义立而德不...
    大珊老师阅读 495评论 0 3
  • 这是一个刚学会说话的小朋友的日常 01 早上闹钟响了,我刚要起身,小为醒了。 哼哼唧唧的说,妈妈,不起床,妈妈再睡...
    小为的日常阅读 261评论 0 0