八皇后问题介绍

八皇后问题是一个古老而著名的数学问题,最早由国际西洋棋棋手马克斯·贝瑟尔于1848年提出。问题表述为:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上。

这个问题不仅是一个有趣的谜题,而且是计算机科学中回溯算法的一个经典案例。回溯算法通过逐步构建解决方案,并在发现冲突时回溯到之前的步骤,从而找到所有可能的解决方案。

在八皇后问题中,一种常见的解决方法是使用一个长度为8的数组来表示皇后的位置。数组的每个元素代表一列,其值表示该列上的皇后所在的行号。通过全排列的方式生成所有可能的列排列,并检查每种排列是否满足皇后不互相攻击的条件。

除了全排列解法外,还有其他一些优化方法可以提高求解八皇后问题的效率。例如,可以使用位运算来快速判断两个皇后是否在同一对角线上,或者使用递归和迭代的方法来减少循环次数。

八皇后问题不仅在数学和计算机科学领域具有重要地位,还经常被用作教学和测试算法复杂度的示例。此外,该问题还可以推广为更一般的n皇后摆放问题,即在n×n的棋盘上摆放n个皇后,使其不互相攻击。这个问题也有许多有趣的解法和应用。

大模型介绍

当前常见的大模型有文心一言、ChatGPT,以及开源的ChatGLM等,今天我们就以八皇后问题来考一下这三个大模型。让我们看看它们的表现吧!

我认为c语言对它们可能有点难,就先用lisp试试。

hy lisp代码

请用hy语言写八皇后问题解决的代码

(import itertools *)  
(import toolz.itertoolz [first])
  
(defn solve-n-queens [n]  
  (defn is-valid [board row col]  
    (setv queens (map second board))  
    (and (not (in col queens))  
         (notany (fn [i] (= 0 (- col (nth queens i)) (- row i))))  
         (notany (fn [i] (= 0 (+ col (nth queens i)) (- row i))))))  
  
  (defn solve [board row]  
    (if (= row n)  
      (list board)  
      (let [cols (range n)]  
        (filter  
          (fn [col]  
            (is-valid board row col))  
          (map  
            (fn [col]  
              (solve (assoc board row col) (+ row 1)))  
            cols)))))  
  
  (first (solve {} 0)))  
  
(print (solve-n-queens 8))

这个(import [itertools *])  直接有报错,改写成(import itertools *)

报错:NameError: name 'first' is not defined ,发现可以先导入first:(import toolz.itertoolz [first])

报错:    (solve (assoc board row col) (+ row 1)))
NameError: name 'assoc' is not defined 先搁置。

本来以为lisp代码是最简单的,但是问题多多,先搁置,看来要调整下阶段工作重心了。

chatgpt的c语言代码

chatgpt的这个c语言的pass

#include <stdio.h>
#include <stdbool.h>

#define N 8

bool isSafe(int board[N][N], int row, int col) {
    int i, j;

    for (i = 0; i < col; i++)
        if (board[row][i])
            return false;

    for (i = row, j = col; i >= 0 && j >= 0; i--, j--)
        if (board[i][j])
            return false;

    for (i = row, j = col; j >= 0 && i < N; i++, j--)
        if (board[i][j])
            return false;

    return true;
}

bool solveNQUtil(int board[N][N], int col) {
    if (col >= N)
        return true;

    for (int i = 0; i < N; i++) {
        if (isSafe(board, i, col)) {
            board[i][col] = 1;

            if (solveNQUtil(board, col + 1))
                return true;

            board[i][col] = 0;
        }
    }

    return false;
}

void printSolution(int board[N][N]) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++)
            printf("%d ", board[i][j]);
        printf("\n");
    }
}

void solveNQ() {
    int board[N][N] = { {0, 0, 0, 0, 0, 0, 0, 0},
                        {0, 0, 0, 0, 0, 0, 0, 0},
                        {0, 0, 0, 0, 0, 0, 0, 0},
                        {0, 0, 0, 0, 0, 0, 0, 0},
                        {0, 0, 0, 0, 0, 0, 0, 0},
                        {0, 0, 0, 0, 0, 0, 0, 0},
                        {0, 0, 0, 0, 0, 0, 0, 0},
                        {0, 0, 0, 0, 0, 0, 0, 0} };

    if (solveNQUtil(board, 0) == false) {
        printf("Solution does not exist");
        return;
    }

    printSolution(board);
}

int main() {
    solveNQ();
    return 0;
}

文心一言3.5的c代码

文心一言的刚开始缺失了int j 声明而报错,加上之后,发现结果错误:

#include <stdio.h>  
#include <stdbool.h>  
  
#define N 8  
  
bool is_safe(int board[], int row, int col) {  
    int i;  
    int j;  
    // 检查列上是否有冲突  
    for (i = 0; i < row; i++) {  
        if (board[i] == col)  
            return false;  
    }  
  
    // 检查左上方是否有冲突  
    for (i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {  
        if (board[i] == j)  
            return false;  
    }  
  
    // 检查右上方是否有冲突  
    for (i = row - 1, j = col + 1; i >= 0 && j < N; i--, j++) {  
        if (board[i] == j)  
            return false;  
    }  
  
    return true;  
}  
  
bool solve_n_queens(int board[], int col) {  
    // 如果所有列都已经成功放置了皇后  
    if (col >= N) {  
        // 输出棋盘状态  
        for (int i = 0; i < N; i++) {  
            for (int j = 0; j < N; j++) {  
                printf("%s ", (board[i] == j) ? "Q " : ". ");  
            }  
            printf("\n");  
        }  
        printf("\n");  
        return true; // 找到一个解  
    }  
  
    // 尝试在当前列放置皇后  
    for (int i = 0; i < N; i++) {  
        if (is_safe(board, i, col)) {  
            board[i] = col; // 在 (i, col) 位置放置皇后  
  
            // 递归地放置下一列的皇后  
            if (solve_n_queens(board, col + 1))  
                return true; // 如果找到一个解,则回溯  
  
            // 如果找不到解,则回溯,重置当前位置  
            board[i] = 0; // 移除 (i, col) 位置的皇后  
        }  
    }  
  
    // 如果所有行都尝试了但都找不到解,则返回 false  
    return false;  
}  
  
int main() {  
    int board[N] = {0}; // 初始化棋盘  
    if (!solve_n_queens(board, 0)) // 从第一列开始放置皇后  
        printf("Solution does not exist\n");  
    return 0;  
}

运算结果:

./a.out 
.  .  .  .  .  .  .  Q  
Q  .  .  .  .  .  .  .  
Q  .  .  .  .  .  .  .  
Q  .  .  .  .  .  .  .  
Q  .  .  .  .  .  .  .  
Q  .  .  .  .  .  .  .  
Q  .  .  .  .  .  .  .  
Q  .  .  .  .  .  .  .  

简单调了下,没有调通。先搁置。

ChatGLM3的c语言代码
 

刚开始给的代码: 

#include <stdio.h>

void print_board(int board[9][9]) {
   for (int i = 0; i < 9; i++) {
       for (int j = 0; j < 9; j++) {
           printf("%d ", board[i][j]);
       }
       printf("\n");
   }
}

int is_safe(int board[9][9], int row, int col) {
   for (int i = 0; i < 9; i++) {
       if (board[row][i] == col || board[i][col] == col) {
           return 0;
       }
   }
   return 1;
}

void solve(int board[9][9], int row, int n) {
   if (row == n) {
       print_board(board);
       printf("\n");
       return;
   }
   for (int col = 0; col < 9; col++) {
       if (is_safe(board, row, col)) {
           board[row][col] = col + 1;
           solve(board, row + 1, n);
           board[row][col] = 0;
       }
   }
}

int main() {
   int board[9][9] = {{0, 0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0, 0}};
   int n = 8;
   solve(board, 0, n);
   return 0;
}

不明白为什么这里用了9。文心一言说:这段代码的目标是解决九宫数独(Sudoku)问题,但实际上它试图解决的是8皇后问题(N Queens Problem),只是棋盘大小和变量命名有些混淆。数独和8皇后是两个不同的问题,但它们都涉及到在棋盘上放置一些“皇后”或“数字”以避免冲突。

重新问了它问题“再写一个八皇后的实现程序,用c ,注意,不是数独”,这回至少棋盘是对的了

改变了问题策略之后的c代码 

#include <stdio.h>

void print_board(int board[8][8]) {
   for (int i = 0; i < 8; i++) {
       for (int j = 0; j < 8; j++) {
           printf("%2d ", board[i][j]);
       }
       printf("\n");
   }
}

int is_safe(int board[8][8], int row, int col) {
   for (int i = 0; i < 8; i++) {
       if (board[i][col] == 1 && row != i) {
           return 0;
       }
       if (board[row][i] == 1 && col != i) {
           return 0;
       }
   }
   return 1;
}

void solve(int board[8][8], int row, int n) {
   if (row == n) {
       print_board(board);
       printf("\n");
       return;
   }
   for (int col = 0; col < 8; col++) {
       if (is_safe(board, row, col)) {
           board[row][col] = 1;
           solve(board, row + 1, n);
           board[row][col] = 0;
       }
   }
}

int main() {
   int board[8][8] = {{0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0}};
   int n = 8;
   solve(board, 0, n);
   return 0;
}

拿着这段代码去问文心一言,它说:

这段八皇后问题的代码已经基本正确,但is_safe函数缺少了斜线方向的冲突检查。在八皇后问题中,我们需要确保新的皇后在放置时不会与任何其他皇后处于同一行、同一列或同一对角线上。

下面是修改后的is_safe函数,它现在包含了斜线方向的冲突检查:

int is_safe(int board[8][8], int row, int col) {  
   for (int i = 0; i < 8; i++) {  
       // 检查列上是否有冲突  
       if (board[i][col] == 1) {  
           return 0;  
       }  
       // 检查主对角线上是否有冲突  
       if (row - i >= 0 && col - i >= 0 && board[row - i][col - i] == 1) {  
           return 0;  
       }  
       // 检查次对角线上是否有冲突  
       if (row - i >= 0 && col + i < 8 && board[row - i][col + i] == 1) {  
           return 0;  
       }  
   }  
   return 1;  
}

将主次对角线的代码修改成文心这段代码,整个程序终于运行成功了!

经过文心一言修改后的完成代码

#include <stdio.h>

void print_board(int board[8][8]) {
   for (int i = 0; i < 8; i++) {
       for (int j = 0; j < 8; j++) {
           printf("%2d ", board[i][j]);
       }
       printf("\n");
   }
}

int is_safe(int board[8][8], int row, int col) {
   for (int i = 0; i < 8; i++) {
       if (board[i][col] == 1 && row != i) {
           return 0;
       }
       if (board[row][i] == 1 && col != i) {
           return 0;
       }
       // 检查主对角线上是否有冲突  
       if (row - i >= 0 && col - i >= 0 && board[row - i][col - i] == 1) {  
           return 0;  
       }  
       // 检查次对角线上是否有冲突  
       if (row - i >= 0 && col + i < 8 && board[row - i][col + i] == 1) {  
           return 0;  
       }  
   }
   

   return 1;
}

void solve(int board[8][8], int row, int n) {
   if (row == n) {
       print_board(board);
       printf("\n");
       return;
   }
   for (int col = 0; col < 8; col++) {
       if (is_safe(board, row, col)) {
           board[row][col] = 1;
           solve(board, row + 1, n);
           board[row][col] = 0;
       }
   }
}

int main() {
   int board[8][8] = {{0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 0, 0, 0, 0, 0, 0, 0}};
   int n = 8;
   solve(board, 0, n);
   return 0;
}

输出显示:

gcc eightqueen_glm3.c 
./a.out
 1  0  0  0  0  0  0  0 
 0  0  0  0  1  0  0  0 
 0  0  0  0  0  0  0  1 
 0  0  0  0  0  1  0  0 
 0  0  1  0  0  0  0  0 
 0  0  0  0  0  0  1  0 
 0  1  0  0  0  0  0  0 
 0  0  0  1  0  0  0  0 

 1  0  0  0  0  0  0  0 
 0  0  0  0  0  1  0  0 
 0  0  0  0  0  0  0  1 
 0  0  1  0  0  0  0  0 
 0  0  0  0  0  0  1  0 
 0  0  0  1  0  0  0  0 
 0  1  0  0  0  0  0  0 
 0  0  0  0  1  0  0  0 

 1  0  0  0  0  0  0  0 
 0  0  0  0  0  0  1  0 
 0  0  0  1  0  0  0  0 
 0  0  0  0  0  1  0  0 
 0  0  0  0  0  0  0  1 
 0  1  0  0  0  0  0  0 
 0  0  0  0  1  0  0  0 
 0  0  1  0  0  0  0  0 

 1  0  0  0  0  0  0  0 
 0  0  0  0  0  0  1  0 
 0  0  0  0  1  0  0  0 
 0  0  0  0  0  0  0  1 
 0  1  0  0  0  0  0  0 
 0  0  0  1  0  0  0  0 
 0  0  0  0  0  1  0  0 
 0  0  1  0  0  0  0  0 

 0  1  0  0  0  0  0  0 
 0  0  0  1  0  0  0  0 
 0  0  0  0  0  1  0  0 
 0  0  0  0  0  0  0  1 
 0  0  1  0  0  0  0  0 
 1  0  0  0  0  0  0  0 
 0  0  0  0  0  0  1  0 
 0  0  0  0  1  0  0  0 

 0  1  0  0  0  0  0  0 
 0  0  0  0  1  0  0  0 
 0  0  0  0  0  0  1  0 
 1  0  0  0  0  0  0  0 
 0  0  1  0  0  0  0  0 
 0  0  0  0  0  0  0  1 
 0  0  0  0  0  1  0  0 
 0  0  0  1  0  0  0  0 

 0  1  0  0  0  0  0  0 
 0  0  0  0  1  0  0  0 
 0  0  0  0  0  0  1  0 
 0  0  0  1  0  0  0  0 
 1  0  0  0  0  0  0  0 
 0  0  0  0  0  0  0  1 
 0  0  0  0  0  1  0  0 
 0  0  1  0  0  0  0  0 

 0  1  0  0  0  0  0  0 
 0  0  0  0  0  1  0  0 
 1  0  0  0  0  0  0  0 
 0  0  0  0  0  0  1  0 
 0  0  0  1  0  0  0  0 
 0  0  0  0  0  0  0  1 
 0  0  1  0  0  0  0  0 
 0  0  0  0  1  0  0  0 

总结:

虽然很多代码生成并不能一次性成功,但是在多个大模型交叉调试的情况下,还是能满足我们的日常编程需求的。

调试

hy (import [itertools *])  直接有报错

(import [itertools *])  
Traceback (most recent call last):
  File "stdin-0bab587d83cb82a8d732b16c55398dcca4b8b02b", line 1
    (import [itertools *])  
            ^
hy.errors.HySyntaxError: parse error for pattern macro 'import': got unexpected token: hy.models.List([
  hy.models.Symbol('itertools'),
  hy.models.Symbol('*')]), expected: end of input

直接写成(import itertools *)

hy报错:NameError: name 'first' is not defined

发现可以先导入first:(import toolz.itertoolz [first])

hy报错:NameError: name 'assoc' is not defined

    (solve (assoc board row col) (+ row 1)))
NameError: name 'assoc' is not defined
先搁置。

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐