回溯法是一种非常常见的算法,八皇后问题和迷宫问题都可以使用回溯法进行求解。以下是百度百科中对于回溯法的解释
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
——百度百科
回溯法采用一种试探回溯的思想。我们从一个一个分支逐步深入,一旦发现当前分支不是我们所需要的,就排除当前分支,然后回到上一步试探其他分支。迷宫问题就是一种常见的使用回溯法的算法问题。事实上,在现实生活中走迷宫我们也经常使用这种试探的走法。
除了迷宫问题,全排列问题,八皇后问题也都是回溯法的典型问题
八皇后问题
问题表述为:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
对于八皇后问题,我们采用逐行试探的方法。先在当前行找到一个符合条件的位置放置皇后,如果找不到,就回溯一行排除当前位置继续寻找,直到在最后一行找到一个合适的位置,就可以得到一个解。
一下是四皇后问题的一个解的寻找过程。首先在(0,0)处放置皇后,转移到行1,查找到第一个合法的位置为(1,3)。
接着搜寻行2,发现没有符合条件的位置,于是回溯到行1,继续寻找下一个合法的位置(1,4)。
继续试探到行2,找到了一个合法的位置(2,1)。
发现在这种情况下行3没有合法的位置,回溯到行2,发现行2剩余的位置也没有合法的,回溯到行1,行1已经没有剩余位置,直接回溯到第0行。
接着试探,起始位置为(0,1)。第1行试探,皇后放在(1,3)
第2行,皇后放在(2,0)。第3行,皇后放在(3,2)。四皇后问题的第一个解找到。
代码实现中特别需要关注的问题是循环何时终止,以及对于边界的处理。
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
| # include <stdio.h> # include <stdbool.h> # define QUEENS 4 # define EMPTY 0 # define FULL 1
int checkboard[QUEENS][QUEENS] = { 0 }; int boardrow[QUEENS] = { 0 };
bool collide(int x, int y) { int i = x - 1, j = y - 1, k = y + 1; while (i >= 0 && (j >= 0 || k < QUEENS)) { if (checkboard[i][y] == FULL) return true; if (j >= 0 && checkboard[i][j--] == FULL) return true; if (k < QUEENS && checkboard[i][k++] == FULL) return true; i--; } return false; }
void drawBoard() { printf("---------------\n"); for (int i = 0; i < QUEENS; i++) { for (int j = 0; j < QUEENS; j++) { printf("%d | ", checkboard[i][j]); } printf("\n---------------\n"); } printf("\n"); }
int Queen() { int x = 0, y = 0; int numOfSol = 0; while (x >= 0 || y < QUEENS) {
if (x >= QUEENS) { numOfSol++; x--; drawBoard(); y = boardrow[x]; checkboard[x][y++] = EMPTY; } else if (y >= QUEENS) { x--; if (x < 0) break; y = boardrow[x]; checkboard[x][y++] = EMPTY; } else if (collide(x, y)) { y++; } else { checkboard[x][y] = FULL; boardrow[x++] = y; y = 0; } } return numOfSol; }
int main() { int c = Queen(); printf("Number of Solution: %d", c); }
|
这里循环结束的终点条件是当回溯到第0行第4列时,就会继续回溯到第-1行,也就是x<0时结束整个循环。