这是经典的分治算法问题。我们有一个大小为2^n * 2^n的棋盘,想要用L形方块填满它。我们知道棋盘上有一个方块不能被覆盖。这个问题也被称为三格图案问题(有点类似)。
问题
我的解决方案适用于n = 1和n = 2。但是当我想进一步推广解决方案(n > 2)时,我无法填满所有方块,其中一些包含错误的L形方块部分。
程序结构
输入
用户输入n
和棋盘上缺失方块t
的位置。
输出
我们打印填有“三格图案”的棋盘。我们为每个“三格图案”分配一个值。缺失的方块始终得到零值,每个“三格图案”都包含一个整数值(1、2、3……)。
解决方案
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
void recursiveSolve(int m, int A[m][m], int A_row, int A_col, int t_row, int t_y, int currBlockNum, int boardSize);
int main(void) {
int n, m;
do {
printf("Give n > 0: ");
scanf("%d", &n);
} while (n <= 0);
m = pow(2, n);
int A[m][m];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < m; ++j) {
A[i][j] = -1;
}
}
int t_row, t_col;
do {
printf("Give missing square row coordinate: ");
scanf("%d", &t_row);
printf("Give missing square column coordinate: ");
scanf("%d", &t_col);
} while (t_row >= m || t_col >= m);
A[t_row][t_col] = 0;
recursiveSolve(m, A, 0, 0, t_row, t_col, 1, m);
for (int i = 0; i < m; ++i) {
for (int j = 0; j < m; ++j) {
printf("%2d ", A[i][j]);
}
printf("\n");
}
return 0;
}
void recursiveSolve(int m, int A[m][m], int A_row, int A_col, int t_row, int t_col, int currBlockNum, int boardSize) {
if (boardSize == 2) { // fill with L shaped block the area that is blank (no block exist).
// check first which part of our board if filled up with a block
// and then paint the other.
if (A[A_row][A_col] != -1) { // block exist at the top-left corner
A[A_row+1][A_col] = currBlockNum; // paint the bottom-left corner
A[A_row+1][A_col+1] = currBlockNum; // paint the bottom-right corner
A[A_row][A_col+1] = currBlockNum; // paint the top-right corner
} else if (A[A_row][A_col+1] != -1) { // block exist at the top-right corner
A[A_row][A_col] = currBlockNum; // paint the top-left corner
A[A_row+1][A_col] = currBlockNum; // paint the bottom-left corner
A[A_row+1][A_col+1] = currBlockNum; // paint the bottom-right corner
} else if (A[A_row+1][A_col] != -1) { // block exist at the bottom-left corner
A[A_row][A_col] = currBlockNum;
A[A_row][A_col+1] = currBlockNum;
A[A_row+1][A_col+1] = currBlockNum;
} else { // block exist at the bottom-right corner
A[A_row][A_col] = currBlockNum;
A[A_row][A_col+1] = currBlockNum;
A[A_row+1][A_col] = currBlockNum;
}
} else {
int A_halfSize = boardSize / 2;
// the bellow calculations allow us to check which
// sub-partition of our board includes the missing block,
// as well as how we should paint the center L shaped block.
int A_rowCenter = A_row + A_halfSize;
int A_colCenter = A_col + A_halfSize;
if (t_row < A_rowCenter) { // missing block in top half
if (t_col < A_colCenter ) { // missing block is in top left half
A[A_rowCenter][A_colCenter-1] = currBlockNum;
A[A_rowCenter][A_colCenter] = currBlockNum;
A[A_rowCenter-1][A_colCenter] = currBlockNum;
} else { // missing block is in top right half
A[A_rowCenter-1][A_colCenter-1] = currBlockNum;
A[A_rowCenter][A_colCenter-1] = currBlockNum;
A[A_rowCenter][A_colCenter] = currBlockNum;
}
} else { // missing block in bottom half
if (t_col < A_colCenter ) { // missing block is in bottom left half
A[A_rowCenter][A_colCenter] = currBlockNum;
A[A_rowCenter-1][A_colCenter] = currBlockNum;
A[A_rowCenter-1][A_colCenter-1] = currBlockNum;
} else { // missing block is in bottom right half
A[A_rowCenter][A_colCenter-1] = currBlockNum;
A[A_rowCenter-1][A_colCenter-1] = currBlockNum;
A[A_rowCenter-1][A_colCenter] = currBlockNum;
}
}
// solve each sub-partion recursively
// top-right sub-partion
recursiveSolve(m, A, A_row, A_colCenter, t_row, t_col, ++currBlockNum, A_halfSize);
// bottom-right sub-partion
recursiveSolve(m, A, A_rowCenter, A_colCenter, t_row, t_col, ++currBlockNum, A_halfSize);
// bottom left sub-partition
recursiveSolve(m, A, A_rowCenter, A_col, t_row, t_col, ++currBlockNum, A_halfSize);
// top-left sub-partition
recursiveSolve(m, A, A_row, A_col, t_row, t_col, ++currBlockNum, A_halfSize);
}
}