經(jīng)典算法之棋盤覆蓋問題 --分治法

分治法——棋盤覆蓋問題
棋盤覆蓋問題。有一個2k?2k2k?2k的方格棋盤,恰有一個方格是黑色的诱告,其他為白色。你的任務(wù)是用包含3個方格的L型牌覆蓋所有白色方格民晒。黑色方格不能被覆蓋精居,且任意一個白色方格不能同時被兩個或更多牌覆蓋。如圖所示為L型牌的4種旋轉(zhuǎn)方式潜必。

分治三步驟
劃分問題:將2k?2k2k?2k的棋盤劃分為2k?1?2k?12k?1?2k?1這樣的子棋盤4塊靴姿。
遞歸求解:遞歸填充各個格子,填充分為四個情況磁滚,在下面會有解釋佛吓,遞歸出口為k=0k=0也就是子棋盤方格數(shù)為1。
合并問題:不需要合并子問題垂攘。
遞歸填充的四種情況
如果黑方塊在左上子棋盤维雇,則遞歸填充左上子棋盤;否則填充左上子棋盤的右下角晒他,將右下角看做黑色方塊吱型,然后遞歸填充左上子棋盤。
如果黑方塊在右上子棋盤陨仅,則遞歸填充右上子棋盤津滞;否則填充右上子棋盤的左下角,將左下角看做黑色方塊灼伤,然后遞歸填充右上子棋盤触徐。
如果黑方塊在左下子棋盤,則遞歸填充左下子棋盤饺蔑;否則填充左下子棋盤的右上角锌介,將右上角看做黑色方塊,然后遞歸填充左下子棋盤。
如果黑方塊在右下子棋盤孔祸,則遞歸填充右下子棋盤隆敢;否則填充右下子棋盤的右下角,將左上角看做黑色方塊崔慧,然后遞歸填充右下子棋盤拂蝎。

棋盤覆蓋問題分治算法
void chessBoard(int row, int column, int x, int y, int siz) {
// 遞歸出口
if(siz == 1) {
return;
}

// 對半劃分成2^(siz - 1) * 2^(siz - 1)的棋盤
int s = siz / 2;
// L型牌編號自增
int t = ++number;
// 中間點,以此判別(x,y)在哪個子棋盤中
int centerRow = row + s;
int centerColumn = column + s;
// 黑色方格在左上子棋盤
if(x < centerRow && y < centerColumn) {
    chessBoard(row, column, x, y, s);
} else {
    // 不在則填充左上子棋盤的右下角
    chess[centerRow - 1][centerColumn - 1] = t;
    // 然后覆蓋其他格子惶室,注意這時(x,y)要看做已填充位置
    chessBoard(row, column, centerRow - 1, centerColumn - 1, s);
}

// 黑色方格在右上子棋盤
if(x < centerRow && y >= centerColumn) {
    chessBoard(row, centerColumn, x, y, s);
} else {
    // 不在則填充右上子棋盤的左下角
    chess[centerRow - 1][centerColumn] = t;
    // 然后覆蓋其他格子温自,注意這時(x,y)要看做已填充位置
    chessBoard(row, centerColumn, centerRow - 1, centerColumn, s);
}

// 黑色方格在左下子棋盤
if(x >= centerRow && y < centerColumn) {
    chessBoard(centerRow, column, x, y, s);
} else {
    // 不在則填充左下子棋盤的右上角
    chess[centerRow][centerColumn - 1] = t;
    // 然后覆蓋其他格子,注意這時(x,y)要看做已填充位置
    chessBoard(centerRow, column, centerRow, centerColumn - 1, s);
}

// 黑色方格在右下子棋盤
if(x >= centerRow && y >= centerColumn) {
    chessBoard(centerRow, centerColumn, x, y, s);
} else {
    // 不在則填充右下子棋盤的左上角
    chess[centerRow][centerColumn] = t;
    // 然后覆蓋其他格子皇钞,注意這時(x,y)要看做已填充位置
    chessBoard(centerRow, centerColumn, centerRow, centerColumn, s);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
測試主程序

include <iostream>

using namespace std;

const int maxNum = 1 << 10;
// 棋盤
int chess[maxNum][maxNum];
// L型牌編號
int number;

void chessBoard(int row, int column, int x, int y, int siz) {
// 遞歸出口
if(siz == 1) {
return;
}

// 對半劃分成2^(siz - 1) * 2^(siz - 1)的棋盤
int s = siz / 2;
// L型牌編號自增
int t = ++number;
// 中間點悼泌,以此判別(x,y)在哪個子棋盤中
int centerRow = row + s;
int centerColumn = column + s;
// 黑色方格在左上子棋盤
if(x < centerRow && y < centerColumn) {
    chessBoard(row, column, x, y, s);
} else {
    // 不在則填充左上子棋盤的右下角
    chess[centerRow - 1][centerColumn - 1] = t;
    // 然后覆蓋其他格子,注意這時(x,y)要看做已填充位置
    chessBoard(row, column, centerRow - 1, centerColumn - 1, s);
}

// 黑色方格在右上子棋盤
if(x < centerRow && y >= centerColumn) {
    chessBoard(row, centerColumn, x, y, s);
} else {
    // 不在則填充右上子棋盤的左下角
    chess[centerRow - 1][centerColumn] = t;
    // 然后覆蓋其他格子夹界,注意這時(x,y)要看做已填充位置
    chessBoard(row, centerColumn, centerRow - 1, centerColumn, s);
}

// 黑色方格在左下子棋盤
if(x >= centerRow && y < centerColumn) {
    chessBoard(centerRow, column, x, y, s);
} else {
    // 不在則填充左下子棋盤的右上角
    chess[centerRow][centerColumn - 1] = t;
    // 然后覆蓋其他格子馆里,注意這時(x,y)要看做已填充位置
    chessBoard(centerRow, column, centerRow, centerColumn - 1, s);
}

// 黑色方格在右下子棋盤
if(x >= centerRow && y >= centerColumn) {
    chessBoard(centerRow, centerColumn, x, y, s);
} else {
    // 不在則填充右下子棋盤的左上角
    chess[centerRow][centerColumn] = t;
    // 然后覆蓋其他格子,注意這時(x,y)要看做已填充位置
    chessBoard(centerRow, centerColumn, centerRow, centerColumn, s);
}

}

int main() {
// 大小可柿,黑色方格位置
int siz, x, y;
while(true) {
cout << "(x,y)從(0,0)開始,輸入數(shù)據(jù)為0 0 0即結(jié)束程序鸠踪。" << endl;
cout << "請輸入棋盤大小和黑色方格位置(x,y):";
cin >> siz >> x >> y;
// 退出條件
if(siz == 0) {
break;
}
// 涂黑(x,y),初始化L型牌編號
chess[x][y] = number = 1;

    // 分治法填滿棋盤
    chessBoard(0, 0, x, y, siz);

    // 輸出該棋盤
    for(int i = 0; i < siz; i++) {
        for(int j = 0; j < siz; j++) {
            cout << chess[i][j] << "\t";
        }
        cout << endl << endl << endl;
    }
}

return 0;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
輸出數(shù)據(jù)
(x,y)從(0,0)開始,輸入數(shù)據(jù)為0 0 0即結(jié)束程序复斥。
請輸入棋盤大小和黑色方格位置(x,y):2 0 0
1 2

2 2

(x,y)從(0,0)開始,輸入數(shù)據(jù)為0 0 0即結(jié)束程序营密。
請輸入棋盤大小和黑色方格位置(x,y):4 1 1
3 3 4 4

3 1 2 4

5 2 2 6

5 5 6 6

(x,y)從(0,0)開始,輸入數(shù)據(jù)為0 0 0即結(jié)束程序。
請輸入棋盤大小和黑色方格位置(x,y):8 2 2
4 4 5 5 9 9 10 10

4 3 3 5 9 8 8 10

6 3 1 7 11 11 8 12

6 6 7 7 2 11 12 12

14 14 15 2 2 19 20 20

14 13 15 15 19 19 18 20

16 13 13 17 21 18 18 22

16 16 17 17 21 21 22 22

(x,y)從(0,0)開始,輸入數(shù)據(jù)為0 0 0即結(jié)束程序目锭。
請輸入棋盤大小和黑色方格位置(x,y):0 0 0

Process returned 0 (0x0) execution time : 29.988 s
Press any key to continue.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54


作者:Switch_vov
來源:CSDN
原文:https://blog.csdn.net/q547550831/article/details/51541527
版權(quán)聲明:本文為博主原創(chuàng)文章评汰,轉(zhuǎn)載請附上博文鏈接!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侣集,一起剝皮案震驚了整個濱河市键俱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌世分,老刑警劉巖编振,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異臭埋,居然都是意外死亡踪央,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門瓢阴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來畅蹂,“玉大人,你說我怎么就攤上這事荣恐∫盒保” “怎么了累贤?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長少漆。 經(jīng)常有香客問我臼膏,道長,這世上最難降的妖魔是什么示损? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任渗磅,我火速辦了婚禮,結(jié)果婚禮上检访,老公的妹妹穿的比我還像新娘始鱼。我一直安慰自己,他們只是感情好脆贵,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布医清。 她就那樣靜靜地躺著,像睡著了一般丹禀。 火紅的嫁衣襯著肌膚如雪状勤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天双泪,我揣著相機與錄音,去河邊找鬼密似。 笑死焙矛,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的残腌。 我是一名探鬼主播村斟,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼抛猫!你這毒婦竟也來了蟆盹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤闺金,失蹤者是張志新(化名)和其女友劉穎逾滥,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體败匹,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡寨昙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掀亩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舔哪。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖槽棍,靈堂內(nèi)的尸體忽然破棺而出捉蚤,到底是詐尸還是另有隱情抬驴,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布缆巧,位于F島的核電站布持,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏盅蝗。R本人自食惡果不足惜鳖链,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望墩莫。 院中可真熱鬧芙委,春花似錦、人聲如沸狂秦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裂问。三九已至侧啼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間堪簿,已是汗流浹背痊乾。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留椭更,地道東北人哪审。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像虑瀑,于是被迫代替她去往敵國和親湿滓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

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