经典算法之棋盘覆盖问题 --分治法

分治法——棋盘覆盖问题
棋盘覆盖问题。有一个2k∗2k2k∗2k的方格棋盘,恰有一个方格是黑色的,其他为白色。你的任务是用包含3个方格的L型牌覆盖所有白色方格。黑色方格不能被覆盖,且任意一个白色方格不能同时被两个或更多牌覆盖。如图所示为L型牌的4种旋转方式。

分治三步骤
划分问题:将2k∗2k2k∗2k的棋盘划分为2k−1∗2k−12k−1∗2k−1这样的子棋盘4块。
递归求解:递归填充各个格子,填充分为四个情况,在下面会有解释,递归出口为k=0k=0也就是子棋盘方格数为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)开始,输入数据为0 0 0即结束程序。" << 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
输出数据
(x,y)从(0,0)开始,输入数据为0 0 0即结束程序。
请输入棋盘大小和黑色方格位置(x,y):2 0 0
1 2

2 2

(x,y)从(0,0)开始,输入数据为0 0 0即结束程序。
请输入棋盘大小和黑色方格位置(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)开始,输入数据为0 0 0即结束程序。
请输入棋盘大小和黑色方格位置(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)开始,输入数据为0 0 0即结束程序。
请输入棋盘大小和黑色方格位置(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
版权声明:本文为博主原创文章,转载请附上博文链接!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,809评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,189评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,290评论 0 359
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,399评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,425评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,116评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,710评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,629评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,155评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,261评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,399评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,068评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,758评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,252评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,381评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,747评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,402评论 2 358

推荐阅读更多精彩内容