穩(wěn)定/免分割線多米諾骨牌的棋盤覆蓋問題

前言

多米諾骨牌的棋盤覆蓋問題是一類經(jīng)典的數(shù)學(xué)/算法問題。本文討論添加了免分割線約束條件的多米諾骨牌覆蓋問題。

問題描述

多米諾骨牌是 2 × 1 或 1 × 2 的矩形。
考慮用多米諾骨牌覆蓋 m × n棋盤,如果無法通過一條不穿過任何骨牌內(nèi)部的直線,將一種覆蓋方案分割成兩個部分,那么這種覆蓋方案被稱為是穩(wěn)定的。


(a), (b) 是穩(wěn)定的,(c), (d) 是不穩(wěn)定的
(a), (b) 是穩(wěn)定的,(c), (d) 是不穩(wěn)定的

存在性問題:對于 m × n 的棋盤,是否存在穩(wěn)定的多米諾骨牌的覆蓋方案?
計數(shù)問題:對于 m × n 的棋盤,有多少種穩(wěn)定的多米諾骨牌的覆蓋方案?


輸入輸出

Input

多組測試數(shù)據(jù)。每組測試數(shù)據(jù)的第一行包含兩個整數(shù) m 和 n (1 ≤ m, n ≤ 16) 表示矩形的大小。

Output

對于每組測試數(shù)據(jù),輸出一行一個整數(shù)表示對應(yīng)穩(wěn)定多米諾骨牌覆蓋的方案數(shù)。
答案可能很大,輸出模 1000000007 (10^9 + 7) 的結(jié)果。

Input示例

2 2
5 6
8 7
15 16

Output示例

0
6
13514
856463275

問題鏈接

存在性問題

存在性問題在這文章里已經(jīng)解釋得很清楚。在這里只是給出該文章的一些思路和線索。
首先m,n不能都為奇數(shù)。因為當(dāng)兩者都為奇數(shù)時,棋盤格子總數(shù)m × n 為奇數(shù),而骨牌覆蓋格子數(shù)為偶數(shù),所以不存在覆蓋方案。
下面進一步討論m,n的可能取值情況,并假設(shè)m,n不同時為奇數(shù)。根據(jù)對稱性,不妨假設(shè)m≤ n。我們自小到大討論m的可能取值。

  1. m=1或m=2。顯然只有平凡解 (m,n) = (1, 2) 。
  2. m=3或m=4。自左往右分析可能的放置方式。根據(jù)免分割線條件,只能放置成幾種固定模式,且這幾種模式都不能構(gòu)成齊整的右邊緣。
  3. (m,n) = (5,6), (6,8) 時可以構(gòu)造出解。我們將這兩個解看作(m,n) = (奇數(shù) ,偶數(shù)), (偶數(shù),偶數(shù))的基礎(chǔ)解。基于這兩個基礎(chǔ)解,我們能通過擴展方法構(gòu)造出其他(奇數(shù) ,偶數(shù)), (偶數(shù),偶數(shù))情況下的解。擴展方法是將覆蓋最后一列/行的骨牌平移兩個格子,并在平移產(chǎn)生的空隙中插入橫/豎放的骨牌。
  4. (m,n) = (6,6) 時無解。無解的證明方法是反證法+“算兩次”。假設(shè)結(jié)論成立。覆蓋骨牌數(shù)是18。注意到,穿過每條分割線的骨牌數(shù)必須是偶數(shù),否則由該分割線分割的兩部分中的任意份都只有奇數(shù)格子,無法被覆蓋,所以每條分割線至少穿過2個骨牌。另外分割線共有10條,因此總骨牌數(shù)至少為20個。矛盾!

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

  1. M 和 N 至少有一個是偶數(shù)。
  2. M 和 N 都大于 4 。
  3. M 和 N 不同時等于 6 。

計數(shù)問題

棋盤類的計數(shù)問題很容易想到用動態(tài)規(guī)劃求解。但是這里存在一個較大的問題,分割線在水平方向和豎直方向上都不能有分割線,這個性質(zhì)使得我們很難將覆蓋問題切分為更小的子問題求解,也即是說很難直接應(yīng)用動態(tài)規(guī)劃。對于這一類含有全局性質(zhì)的計數(shù)問題,可以考慮用容斥原理計算。將求解具有穩(wěn)定性質(zhì)的覆蓋問題轉(zhuǎn)化成求解無穩(wěn)定性質(zhì)的覆蓋問題。

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

不考慮分割線覆蓋方案稱為完美覆蓋。完美覆蓋的計數(shù)問題可以使用動態(tài)規(guī)劃求解。

假設(shè)已經(jīng)求出了 i × j 棋盤的完美覆蓋數(shù)(Pij)。我們對列運用容斥原理。容斥原理中的Ai表示被i條豎直分割線分割的無橫向分割線的覆蓋方案;S表示所有無橫向分割線的覆蓋方案。為了敘述方便,我們稱若干個Ai的交稱為豎直分割方案。根據(jù)容斥原理,我們需要計算每種豎直分割方案下的無橫向分割線的覆蓋數(shù)(R)。我們使用按行(r)遞推的方式求解R, 其中Ri表示 i × n棋盤的無橫向分割線的覆蓋數(shù), 所以R=Rm。為了求解Ri,我們定義一個豎直分割方案下 i × n棋盤的完美覆蓋數(shù)為SPi,SPi的值等于被豎直分割線切分的所有小棋盤完美覆蓋數(shù)的乘積。假設(shè)豎直方案將棋盤切分為3個小棋盤( i × a, i × b, i × c),其中a+b+c=n。則SPi = Pia × Pib × Pic. 根據(jù)上述定義,Ri的遞推公式如下:

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

遞推原理是將SPk按照位置最高的橫向分割線(rc)將覆蓋方案分為不相交的k類。每條rc將棋盤分為上下兩部分,上部分無橫向分割線,下部分允許有橫向分割線。假設(shè)上部分有l(wèi)行,則該類的覆蓋方案數(shù)為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;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內(nèi)容

  • 參考blog 棋盤覆蓋問題 問題描述 在一個2^k * 2^k個方格組成的棋盤中,有一個方格與其它的不同,若使用以...
    chenhh6701閱讀 3,335評論 0 4
  • 分治策略 本文包括分治的基本概念二分查找快速排序歸并排序找出偽幣棋盤覆蓋最大子數(shù)組 源碼鏈接:https://gi...
    廖少少閱讀 1,867評論 0 7
  • 寬容的早晨仿佛有治愈的魔力,無論在黑暗的 夜睡的多久多沉,當(dāng)菀紅的朝霞打到一片片勁綠的 樹林,泛起橘紅的...
    心的字閱讀 237評論 0 0
  • 【坤卦易傳原文·文言傳(三)】 文言曰:直(1)其正也,方其義(2)也。君子敬以直內(nèi),義以方外(3),敬義立而德不...
    大珊老師閱讀 580評論 0 3
  • 這是一個剛學(xué)會說話的小朋友的日常 01 早上鬧鐘響了,我剛要起身,小為醒了。 哼哼唧唧的說,媽媽,不起床,媽媽再睡...
    小為的日常閱讀 297評論 0 0