八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当n = 1或n ≥ 4时问题有解。
历史 八皇后问题最早是由国际象棋棋手马克斯·贝瑟尔(Max Bezzel)于1848年提出。第一个解在1850年由弗朗兹·诺克(Franz Nauck)给出。并且将其推广为更一般的n皇后摆放问题。诺克也是首先将问题推广到更一般的n皇后摆放问题的人之一。
在此之后,陆续有数学家对其进行研究,其中包括高斯和康托,1874年,S.冈德尔提出了一个通过行列式来求解的方法[2],这个方法后来又被J.W.L.格莱舍加以改进。
1972年,艾兹格·迪杰斯特拉用这个问题为例来说明他所谓结构化编程的能力[3]。他对深度优先搜索回溯算法有着非常详尽的描述2。
八皇后问题在1990年代初期的著名电子游戏《第七访客》和NDS平台的著名电子游戏《雷顿教授与不可思议的小镇》中都有出现。
解题方法 八个皇后在8x8棋盘上共有4,426,165,368(64C8)种摆放方法,但只有92个可行(皇后间互不攻击)的解。如果将旋转和对称的解归为一种的话,则一共有12个独立解,具体如下:
解的个数 下表给出了n皇后问题的解的个数包括独立解U(OEIS数列A002562)以及可行解D(OEIS数列A000170)的个数:
可以注意到六皇后问题的解的个数比五皇后问题的解的个数要少。现在还没有已知公式可以对n计算n皇后问题的解的个数。
示例程序 下面是求解n皇后的C代码,在程序中可以自己设置n个皇后以及选择是否打印出具体解。
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 #include  <stdio.h>  #define  QUEENS       8  #define  IS_OUTPUT    1  int  A[QUEENS + 1 ], B[QUEENS * 3  + 1 ], C[QUEENS * 3  + 1 ], k[QUEENS + 1 ][QUEENS + 1 ];int  inc, *a = A, *b = B + QUEENS, *c = C;void  lay (int  i)  {  int  j = 0 , t, u;   while  (++j <= QUEENS)     if  (a[j] + b[j - i] + c[j + i] == 0 ) {       k[i][j] = a[j] = b[j - i] = c[j + i] = 1 ;       if  (i < QUEENS) lay(i + 1 );       else  {         ++inc;         if  (IS_OUTPUT) {           for  (printf ("(%d)\n" , inc), u = QUEENS + 1 ; --u; printf ("\n" ))             for  (t = QUEENS + 1 ; --t; ) k[t][u] ? printf ("Q " ) : printf ("+ " );           printf ("\n\n\n" );         }       }       a[j] = b[j - i] = c[j + i] = k[i][j] = 0 ;     } } int  main (void )  {  lay(1 );   printf ("%d皇后共计%d个解\n" , QUEENS, inc);   return  0 ; } 
以下列出尼克劳斯·维尔特的Pascal语言程序。此程序找出了八皇后问题的一个解。
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 program  eightqueen1(output);  var  i : integer; q : boolean;    a : array [ 1  .. 8 ] of  boolean;     b : array [ 2  .. 16 ] of  boolean;     c : array [ -7  .. 7 ] of  boolean;     x : array [ 1  .. 8 ] of  integer;   procedure  try ( i : integer; var  q : boolean) ;    var  j : integer;     begin       j := 0 ;     repeat           j := j + 1 ;          q := false;         if  a[ j] and  b[ i + j] and  c[ i - j] then              begin               x[ i    ] := j;             a[ j    ] := false;              b[ i + j] := false;              c[ i - j] := false;             if  i < 8  then                  begin                  try ( i + 1 , q);                 if  not  q then                      begin                       a[ j] := true;                      b[ i + j] := true;                      c[ i - j] := true;                     end                  end               else                   q := true             end      until  q or  (j = 8 );     end ;   begin for  i :=  1  to   8  do  a[ i] := true;for  i :=  2  to  16  do  b[ i] := true;for  i := -7  to   7  do  c[ i] := true;try ( 1 , q);if  q then     for  i := 1  to  8  do  write ( x[ i]:4 ); writeln end .
使用回溯法进行求解八皇后问题
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 #include <stdio.h>  #define  PRINTF_IN 1  int  queens (int  Queens) {    int  i, k, flag, not_finish=1 , count=0 ;          int  a[Queens+1 ];         i=1 ;     a[1 ]=1 ;       printf ("%d皇后的可能配置是:" ,Queens);     while (not_finish){           while (not_finish && i<=Queens){               for (flag=1 ,k=1 ; flag && k<i; k++)                  if (a[k]==a[i])                     flag=0 ;             for  (k=1 ; flag&&k<i; k++)                   if ( (a[i]==a[k]-(k-i)) || (a[i]==a[k]+(k-i)) )                     flag=0 ;             if (!flag){                   if (a[i]==a[i-1 ]){                       i--;                       if (i>1  && a[i]==Queens)                         a[i]=1 ;                       else                          if (i==1  && a[i]==Queens)                             not_finish=0 ;                           else                              a[i]++;                   }else  if (a[i] == Queens)                     a[i]=1 ;                 else                      a[i]++;               }else  if (++i<=Queens)                 if (a[i-1 ] == Queens )                     a[i]=1 ;                   else                      a[i] = a[i-1 ]+1 ;           }         if (not_finish){             ++count;             if (PRINTF_IN){                 printf ((count-1 )%3  ? "   [%2d]:"  : "\n[%2d]:" , count);                                  for (k=1 ; k<=Queens; k++)                  printf (" %d" , a[k]);              }                 if (a[Queens-1 ]<Queens )                 a[Queens-1 ]++;               else                  a[Queens-1 ]=1 ;             i=Queens -1 ;             }     }     return  count; } int  main () {     int  Num ;      printf ("输入一个N皇后数值:" );     scanf ("%d"  , &Num);     printf ("\n%d皇后有%d种配置\n" ,Num,queens(Num)); } 
使用回溯法进行求解八皇后问题(Java版本),可直接复制到 N-Queens - LeetCode (页面存档备份,存于互联网档案馆) 测试。
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 class  Solution  {    public  List<List<String>> solveNQueens (int  n)  {         List<List<String>> results = new  ArrayList <>();                           char [][] result = new  char [n][n];         for  (int  i  =  0 ; i < n; ++i) {             for  (int  j  =  0 ; j < n; ++j) {                 result[i][j] = '.' ;             }         }         backtrack(results, result, 0 );         return  results;     }     private  static  void  backtrack (List<List<String>> results, char [][] result, int  x)  {         for  (int  j  =  0 ; j < result.length; ++j) {             if  (isValid(result, x, j)) {                 result[x][j] = 'Q' ;                 if  (x == result.length - 1 ) {                     showResult(results, result);                                      } else  {                                          backtrack(results, result, x + 1 );                 }                 result[x][j] = '.' ;             }         }     }     private  static  boolean  isValid (char [][] result, int  x, int  y)  {                                             for  (int  i  =  0 ; i < x; ++i) {             if  (result[i][y] == 'Q' ) {                 return  false ;             }         }                                    for  (int  i  =  x - 1 , j = y - 1 ; i >= 0  && j >= 0 ; --i, --j) {             if  (result[i][j] == 'Q' ) {                 return  false ;             }         }                                    for  (int  i  =  x - 1 , j = y + 1 ; i >= 0  && j < result.length; --i, ++j) {             if  (result[i][j] == 'Q' ) {                 return  false ;             }         }         return  true ;     }     private  static  void  showResult (List<List<String>> results, char [][] result)  {         List<String> list = new  ArrayList <>(result.length);         for  (char [] value : result) {             list.add(new  String (value));         }         results.add(list);     } } 
c++
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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 #include  "iostream"  #include  "cmath"  using  namespace  std;  #define  Max 20       int  a[Max];int  show (int  S)         int  i,p,q;     int  b[Max][Max]={0 };            for (i=1 ;i<=S;i++)         {         b[i][a[i]]=1 ;         printf ("(%d,%d)\t" ,i,a[i]);     }     printf ("\n" );     for (p=1 ;p<=S;p++)          {         for (q=1 ;q<=S;q++)         {             if (b[p][q]==1 )                      printf ("x" );             else                  printf ("o" );           }         printf ("\n" );     }     return  0 ; }   int  check (int  k)         int  i;     for (i=1 ;i<k;i++)         {         if ((a[i]==a[k]) || (a[i]-a[k]==k-i)|| (a[i]-a[k]==i-k) )             {             return  0 ;         }     }     return  1 ; }   void  check_m (int  num)         int  k=1 ,count=0 ;     printf ("N皇后問題的所有解(包含經由旋轉的解):\n" );     a[k]=1 ;     while (k>0 )     {         if (k<=num && a[k]<=num)             {             if (check (k)==0 )                 {                 a[k]++;                     }             else              {                 k++;                          a[k]=1 ;                   }         }         else          {             if (k>num)                  {                 count++;                 printf ("[%d]:  " ,count);                 show (num);                 }             k--;                   a[k]++;            }     }     printf ("總共有 %d \n" ,count,"個" ); }   int  main (void )     int  N,d;     do      {         printf ("                  N皇后問題的解(N<20)                  \n" );             printf ("請輸入N的值:_" );                          scanf ("%d" ,&N);             printf ("\n" );             if (N>0 &&N<20 )             {                 check_m (N);                    break ;             }             else              {                 printf ("輸入錯誤,請重新輸入" );                 printf ("\n\n" );                 break ;              }         }     while (1 );     system ("pause" );     return  0 ; } 
大众文化 
电脑游戏《第七访客》中,伊格(Ego,玩家)在史陶夫的府邸的游戏室里碰到的象棋问题正是八个皇后问题。 
 
原文地址:https://zh.wikipedia.org/wiki/%E5%85%AB%E7%9A%87%E5%90%8E%E9%97%AE%E9%A2%98 
在知识共享 署名-相同方式共享 3.0协议 之条款下提供