八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上(斜率为1),问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种方法可以解决此问题。
解决思想:
定义一个全局的8*8数组board[8][8]。因为任意两个皇后不能处于同一行同一列或同一斜线上,因此每一行只能有一个皇后。
写一个判断当前所摆放的皇后是否与前面各行的皇后存在攻击的函数。只需要判断左上,上,右上三个方向是否有皇后即可。
摆放皇后的函数place_queen(int row)。外层循环从0到7,表示逐列的尝试。首先将该行该列的值置1。当行号是0或者无冲突时,调用place_queen(row+1),进入下一行的摆放。如果有冲突,则将该值置0,外层循环加1,即试探该行下一列。
如此往复直到全部8个皇后摆放完成,调用place_board()函数将盘面打印出来。然后将最后一个值置0,再次回溯,找寻第二种方法,直到place_queen(0)中8列全部试过,即找到所有方法为止。
#include <stdio.h> #include <stdlib.h> #include <string.h> int board[8][8]; void print_board(); void place_queen(int row); int conflict(int row,int col); int main() { place_queen(0); return 0; } void print_board() { static int n_solutions=0; n_solutions+=1; int row,col; printf("Solution:%d\n",n_solutions); for(row=0;row<8;row+=1) { for(col=0;col<8;col+=1) { if(board[row][col]) { printf("Q "); } else { printf("- "); } } printf("\n"); } printf("\n"); } int conflict(int row,int col) { int i; for(i=0;i<=row;i+=1) { if(i!=row&&board[i][col]) return 1; if(i>0&&(row-i)>=0&&(col-i)>=0&&board[row-i][col-i]) return 1; if(i>0&&(row-i)>=0&&(col+i)<8&&board[row-i][col+i]) return 1; } return 0; } void place_queen(int row) { int col; for(col=0;col<8;col+=1) { board[row][col]=1; if(row==0||!conflict(row,col)) { if(row<7) place_queen(row+1); else print_board(); } board[row][col]=0; } }