04. 八皇后问题

一、什么是八皇后问题

  八皇后问题是指在 8*8 各的国际棋盘上摆放八个皇后,使其不能互相攻击,即 任意两个皇后都不能处于同一行、同一列或同一斜线上,问一个有多少种摆法。

  八皇后问题算法思路分析:

  1. 第一个皇后先放第一行第一列。
  2. 第二个皇后放在第二行第一列,然后判断是否 OK,如果不 OK,继续放第二列、第三列、依次把所有列都放完,找到一个合适的。
  3. 继续放第三个皇后,还是第一列、第二列 …… 直至第 8 个皇后也能放在一个不冲突的位置,算是找到一个正确解。
  4. 当得到第一个正确解时,在栈回退到上一个栈时,就会开始回溯,即将第一个皇后,放到第一列的所有正确解,全部得到。
  5. 然后回头继续第一个皇后放第二列,后面继续循环执行 1, 2, 3 的步骤。
#include <stdio.h>
#include <math.h>
#include <string.h>

void PlaceQueen(int Array[], int QueenCount, int N);
int Judge(int Array[], int N);
void Print(int Array[], int QueenCount);

int main()
{
    int QueenCount = 8;
    int Array[QueenCount];
    memset(Array, 0, sizeof(Array));

    PlaceQueen(Array, QueenCount, 0);
  
    return 0;
}
/**
 * @brief 放置第N个皇后
 * 
 * @param Array 棋盘
 * @param QueenCount 皇后的个数
 * @param N 第N个皇后
 * 
 * @note PlaceQueen() 每次递归时,进入PlaceQueen()都有for循环,因此会产生回溯
 */
void PlaceQueen(int Array[], int QueenCount, int N)
{
    if (N == QueenCount)
    {
        PrintEightQueens(Array, QueenCount);
    }
  
    // 依次放入皇后,并判断是否冲突
    for (int i = 0; i < QueenCount; i++)
    {
        // 先将当前这个皇后N放到该函的第一列
        Array[N] = i;
        // 判断当N个皇后放置在i列时是否冲突
        if (Judge(Array, N))
        {
            // 如果不冲突,继续放N+1个皇后
            PlaceQueen(Array, QueenCount, N + 1);
        }
        // 如果冲突,则继续执行Array[N]=i,即将第N个皇后放置本行后移一列的位置
    }
}
/**
 * @brief 判断第N个皇后与前N-1个皇后之间是否有冲突
 * 
 * @param Array 棋盘
 * @param N 第N个皇后
 * @return int 0: 有冲突; 1: 无冲突
 */
int Judge(int Array[], int N)
{
    // 判断第N个皇后与前N-1个皇后之间是否有冲突
    for (int i = 0; i < N; i++)
    {
        // 判断是否在同一列或同一斜线上
        // 同一条斜线,角度为45°,斜率为1或-1
        if (Array[i] == Array[N] || abs(Array[N] - Array[i]) == N - i)
        {
            return 0;
        }
  
    }
  
    return 1;
}
/**
 * @brief 打印解法
 * 
 * @param Array 棋盘
 * @param QueenCount 皇后的个数
 */
void PrintEightQueens(int Array[], int QueenCount)
{
    static int count = 0;
    count++;
    printf("第 %d 种解法:\n", count);
    for (int i = 0; i < QueenCount; i++)
    {
        printf("第 %d 个皇后放在第 %d 行,第 %d 列\n", i + 1, i + 1, Array[i] + 1);
    }
    printf("\n");
}

理论上应该创建一个二维数组来表示棋盘,但是实际上可以通过算法,用一个一位数组即可解决问题。对于一维数组 array[i] 而言,数组的下标(i)表示第几行,对应的值表示第几列。数组的第 i+1 个皇后应该放到第 i+1 行,第 array[i]+1 列。

posted @ 2023-06-21 17:13  星光樱梦  阅读(6)  评论(0编辑  收藏  举报