算法竞赛入门经典第八章 递归与分治之棋盘覆盖问题

题目:有一个 2 k ∗ 2 k 2^k*2^k 2k2k的方格棋盘,恰有一个方格是黑色的,其他为白色。你的任务是用包含3个方格的L型牌覆盖所有白色方格。黑色方格不能被覆盖,且任意一个白色方格不能同时被两个或更多牌覆盖。

由于棋盘是 2 k ∗ 2 k 2^k*2^k 2k2k的,很容易在中间横竖各一刀划分为4个 2 k − 1 ∗ 2 k − 1 2^{k-1}*2^{k-1} 2k12k1的小棋盘,继续划分一直到k=1,成为 2 ∗ 2 2*2 22的棋盘。如果k=1,且 2 ∗ 2 2*2 22的棋盘上有一个黑色方块,那么可以用一块L牌覆盖。
算法竞赛入门经典第八章 递归与分治之棋盘覆盖问题_第1张图片
那么其它的不含黑色方块的区域呢?当k=2时,棋盘大小为 4 × 4 4×4 4×4,其上下左右四个区域有一个区域有黑色方块,另外三个没有。那么我们可以用一块L牌覆盖有黑色方块的区域,另外三个区域采用下图的覆盖方式,能够留出一个L型的未覆盖区域,刚好再用一块L牌覆盖。
算法竞赛入门经典第八章 递归与分治之棋盘覆盖问题_第2张图片
这样我们就知道递归的基本思路了:将棋盘划分成四部分,如果:

  1. 左上部分没有黑色方块,将左上部分右下角设置为特殊方块(将被图中紫色L牌覆盖);
  2. 右上部分没有黑色方块,将左上部分左下角设置为特殊方块(将被图中紫色L牌覆盖);
  3. 左下部分没有黑色方块,将左上部分右上角设置为特殊方块(将被图中紫色L牌覆盖);
  4. 右下部分没有黑色方块,将左上部分左上角设置为特殊方块(将被图中紫色L牌覆盖);

每次递归分别检查上下左右四部分,如果有黑色方块则继续递归,否则填充特殊方块。将特殊方块视为黑色方块并再次递归。当棋盘为 2 ∗ 2 2*2 22时填充完毕,当棋盘为 1 ∗ 1 1*1 11时直接返回(base case)。注意全局变量count和局部变量t的使用,count的最终值同时也是使用的L牌块数。

#include
#include
using namespace std;

int count = 1;

void print(vector<vector<int>> s)
{
 for(int i = 0; i < s.size(); i++)
 {
   for(int j = 0; j < s[0].size(); j++)
     cout<<s[i][j]<<", ";
   cout<<endl;
 }
}

void cover_board (vector< vector<int> > &board, int size, int lu_r, int lu_c, int black_r, int black_c) //black_r和black_c记录黑色方块所在行和列。lu_x和lu_y记录当前棋盘左上角的行和列。
{
 if(size == 1) return;
 int n = size / 2;
 int t = count++;

 if(black_r < lu_r + n && black_c < lu_c + n) //黑色方块在左上角
   cover_board(board, n, lu_r, lu_c, black_r, black_c);
 else {board[lu_r + n - 1][lu_c + n - 1] = t; cover_board(board, n, lu_r, lu_c, lu_r + n - 1, lu_c + n - 1);}

 if(black_r >= lu_r + n && black_c < lu_c + n) //黑色方块在左下角
   cover_board(board, n, lu_r + n, lu_c, black_r, black_c);
 else {board[lu_r + n][lu_c + n - 1] = t; cover_board(board, n, lu_r+n, lu_c, lu_r + n, lu_c + n-1);}

 if(black_r < lu_r+n && black_c >= lu_c + n) //黑色方块在右上角
   cover_board(board, n, lu_r, lu_c+n, black_r, black_c);
 else {board[lu_r + n - 1][lu_c + n] = t; cover_board(board, n, lu_r, lu_c+n, lu_r + n-1, lu_c + n);}

 if(black_r >= lu_r+n && black_c >= lu_c + n) //黑色方块在右下角
   cover_board(board, n, lu_r+n, lu_c+n, black_r, black_c);
 else {board[lu_r + n][lu_c + n] = t; cover_board(board, n, lu_r+n, lu_c+n, lu_r + n, lu_c + n);}
}

int main()
{
 int size=8;
 vector<vector<int>> chess_board(size, vector<int> (size, 0));
 int r=3, c=5;
 cover_board(chess_board, size, 0, 0, r, c);
 print(chess_board);
 return 0;
}

size=8,黑色方块位于第四排第六列时输出结果:
算法竞赛入门经典第八章 递归与分治之棋盘覆盖问题_第3张图片
size=16,黑色方块位于第四排第六列时输出结果:
算法竞赛入门经典第八章 递归与分治之棋盘覆盖问题_第4张图片

你可能感兴趣的:(算法竞赛入门经典)