八皇后问题 (Eight queens puzzle)

问题

在 8*8 的国际象棋棋盘上有 8 个皇后,如何摆放使这 8 个皇后互不威胁对方。 换句话说就是,没有任何 2 个皇后在同一行,同一列,同一对角线上

思路

利用回溯法,将行作为深度,列作为 n 叉树的分叉

假设将棋盘分成 8 行,从上到下编号为 8-1
分成 8 列,从左到右编号为 A-H

求解过程如下:
一行一行放,首先保证了皇后放在不同的行

  1. 是否放满了 8 个皇后,否,继续
    在 8-A 放上一个皇后
    查看是否可放,可行,继续下一步(深度 + 1)

  2. 是否放满了 8 个皇后,否,继续
    在 7-A 放上一个皇后
    查看是否可放,不可行(与 8-A 这个皇后在同一列上),放弃这个子树,继续搜索下一个(列 + 1)

  3. 是否放满了 8 个皇后,否,继续
    在 7-B 放上一个皇后
    查看是否可放,不可行(与 8-A 这个皇后在同一列上),放弃这个子树,继续搜索下一个(列 + 1)

  4. 是否放满了 8 个皇后,否,继续
    在 7-C 放上一个皇后
    查看是否可放,可行,继续下一步(深度 + 1)

  5. 是否放满了 8 个皇后,否,继续
    在 6-A 放上一个皇后
    查看是否可放,不可行(与 8-A 这个皇后在同一列上),放弃这个子树,继续搜索下一个(列 + 1)

  6. ...

  7. 是否放满了 8 个皇后,否,继续
    在 1-D 放上一个皇后
    查看是否可放,可行继续下一步(深度 + 1)

  8. 是否放满了 8 个皇后,是,输出解,回到上一步(深度 - 1)

  9. 直到搜索完所有情况

代码

#include <stdlib.h>
#include <stdio.h>

#define TRUE        1
#define FALSE       0
#define NUM_QUEENS  8

void output(int *queens)
{
    for (int i = 0; i < NUM_QUEENS; i++) {
        printf("%d ", queens[i]);
    }
    printf("\n");
}

/*
 * 查看是否和 row 以上几行的皇后在同一列或同一对角线
 */
int constraint(int *queens, int row)
{
    for (int i = 0; i < row; i++) {
        if (queens[row] == queens[i]
            || abs(i - row) == abs(queens[row] - queens[i])) {
            return FALSE;
        }
    }
    return TRUE;
}

void eight_queens_puzzle_iter(int *queens, int row)
{
    if (row == NUM_QUEENS) {
        output(queens);
        return;
    }
    for (int col = 0; col < NUM_QUEENS; col++) {
        queens[row] = col;
        if (constraint(queens, row) == TRUE) {
            eight_queens_puzzle_iter(queens, row + 1);
        }
    }
}

void eight_queens_puzzle(int *queens)
{
    eight_queens_puzzle_iter(queens, 0);
}

int main(int argc, char *argv[])
{
    int queens[NUM_QUEENS] = {0};

    eight_queens_puzzle(queens);

    return 0;
}