棋盘覆盖问题——分治法
问题描述
有一个 x<img src="https://latex.codecogs.com/gif.latex?2%5Ek" alt="2^k" class="mathcode" />&nbsp;(k&gt;0)的棋盘,恰好有一个方格与其他方格不同,称之为特殊方格。现在要用如下图所示的L形骨牌覆盖除了特殊方格以外的其他全部方格,骨牌可以任意旋转,并且任何两个骨牌不能重复。请给出一种覆盖方式。

样例:
输入:
输出:
思路——分治法:
将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同。
递归地解决这些子问题,然后将各个子问题的解合并得到原问题的解。
就是将规模为n的问题自顶向下分解,直到小问题分解到足够小,可以解决时,再自底向上合并,从而得到原来的解。
当k=0(棋盘只有1格),特殊点只能唯一,L骨牌数为0
当k >0,则可将 2*kⅹ2*k 棋盘分割为 4个 2*k-1ⅹ2*k-1 的子棋盘

判断特殊点在哪一个子棋盘中,用一块L骨牌放在其它三个子棋盘的连接处
以此类推,则最后可将每个子棋盘划分为1格的棋盘,结束递归
代码实现:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include <iomanip>
using namespace std;
int arr[1000][1000];
int num = 0;
void ChessBoard(int x, int y, int a, int b, int length);
int main() {
//棋盘大小
int k;
int length;
cout << "请输入k:";
cin >> k;
length = pow(2,k);
//空白点坐标
int a, b;
cout << "请输入空格位置:";
cin >> a >> b;
cout << endl;
arr[a][b] = 0;//标点用0表示
ChessBoard(1, 1, a, b, length);
cout << setw(5);
for (int i = 1; i <= length; i++) {
for (int j = 1; j <= length; j++) {
cout << arr[i][j] << setw(5);
}
cout << endl;
}
return 0;
}
void ChessBoard(int x, int y, int a, int b, int length) {
if (length == 1) {
return;
}
int h = length / 2;//分割棋盘
int t = ++num;//骨牌号,从1开始,相同数字代表是同一块
//以“田”的左下角为(1,1)
//左下角
if (a < x + h && b < y + h) {
ChessBoard(x, y, a, b, h);
}
else {
arr[x + h - 1][y + h - 1] = t;
ChessBoard(x, y, x + h - 1, y + h - 1, h);
}
//左上角
if (a < x + h && b >= y + h) {
ChessBoard(x, y + h, a, b, h);
}
else {
arr[x + h - 1][y + h] = t;
ChessBoard(x, y + h, x + h - 1, y + h, h);
}
//右下角
if (a >= x + h && b < y + h) {
ChessBoard(x + h, y, a, b, h);
}
else {
arr[x + h][y + h - 1] = t;
ChessBoard(x + h, y, x + h, y + h - 1, h);
}
//右上角
if (a >= x + h && b >= y + h) {
ChessBoard(x + h, y + h, a, b, h);
}
else {
arr[x + h][y + h] = t;
ChessBoard(x + h, y + h, x + h, y + h, h);
}
}
参考资料:《计算机算法设计与分析(第四版)》

浙公网安备 33010602011771号