
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:
在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
思路:
- 一维数组array存放皇后位置,array[i]=j 表示i行j列有一个皇后。
- 判断该位置放置皇后是否合法。
- 该位置合法,则进行下一行放置。
- 该位置非法则列值j++,进行第2步的判断。
- 当放满8个皇后(即i从0–>7)时,找到结果+1。
- 当某行中的列值(即array[i])>=8时,说明该行在前面行的摆放情况下无解。
- 则回退到上一行,对上一行的列值j++,进行2步判断。
- 当row回退到第一行(i=0),且第一行的列值超出范围(array[0]>=8)时,代表搜索结束。
- 输出所有可行解。
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 <stdlib.h>
#define N 8
int check(int *q, int row) { if(row == 0) { return 1; } else { int y; int x0 = q[row]; for(y = 0; y < row; y++) { int x = q[y]; if(x == x0) return 0; else if(x - x0 == row - y) return 0; else if(x0 - x == row - y) return 0; } } return 1; }
int queen() {
int q[N] = {0}; int found = 0; int row = 0; int done = 0;
while(done == 0) { if(check(q, row)) { if(row == N-1) { found++; } else { row++; q[row] = 0; continue; } } q[row] += 1; while(q[row] >= N) { row--; if(row >= 0) { q[row]++; } else { done = 1; break; } } } return found; }
int main() { int found; found = queen(); printf("found = %d\n",found); 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
| int search(int *array, int row) { int count = 0; int i; for(i = 0; i < N; i++) { array[row] = i; if(check(array, row)) { if(row == N - 1) { count++; } else { count += search(array, row + 1); } } } return count; }
int queen() { int array[N] = {0}; return search(array, 0); }
|