Eight queens puzzle 八皇后

From Wikipedia, the free encyclopedia

The eight queens puzzle is the problem of placing eight chess queens on an 8×8 chessboard such that none of them are able to capture any other using the standard chess queen's moves. The queens must be placed in such a way that no two queens attack each other. Thus, a solution requires that no two queens share the same row, column, or diagonal. The eight queens puzzle is an example of the more general n-queens problem of placing n queens on an n×n chessboard, where solutions exist only for n = 1 or n ≥ 4.

利用C++的STL遍历全排列实现

首先生成一个含有1-8整数元素的一维数组,数组中的每个元素的索引表示ROW,对应的值表示COLUMN(也可以交换)。这样就达到了不在同行不在同列的放置要求,为了达到不在对角线的要求,只需满足索引差的绝对值不等于元素差的绝对值。CHECK函数如下:

int check_cross()
{
 for(size_t i = 0; i < board.size()-1; i++)
 {
  for(size_t j = i+1; j < board.size(); j++)
  {
   if((j-i) == (size_t)abs(board[i]-board[j]))
    return 1;
  }
 }
 return 0;
}

为了生成所有可能结果,对该数组进行全排列,输出每个符合要求的排列即可。

void put_chess(int &count)
{
 while(next_permutation(board.begin(), board.end()))
 {
  if(!check_cross())
  {
   show_result();
   count++;
  }
 }
}

利用backtracking实现(迭代法)

同样含有一个CHECK函数,由于这次的数组并非全排列,所以需要增加一个元素是否相同的判断

int check(int k, int *x)
{
 int i;
 for (i = 0; i < k; i++)
 {
  if ((x[i] == x[k]) | (abs(x[i] - x[k]) == abs(i - k)))
  {
   return -1;
  }
 }
 return 1;
}

首先顺序遍历数组,生成和前面所有元素不冲突的值,如果存在这样的值,那么判断是否走到末尾,如果是那么就找到一组符合条件的值,如果不是末尾则继续循环。如果不存在这样的值,那么进行回溯,改变他前一个的值。

void queens(int n)
{
 int *x;
 x = (int *)malloc(sizeof(int)  * n);
 int k = 0;
 x[0] = 0;
 int count = 0, i = 0;
 while (k >= 0)
 {
  do
  {
   x[k]++;
  } while (x[k] <= n && check(k, x) < 0);
  if (x[k] <= n)
  {
   if (k == n - 1)
   {
    count++;
    printf("\nS.%3d",count);
    for (i = 0; i < n; i++)
    {
     printf("%2d", x[i]);
    }
   }
   else
   {
    k++;
    x[k] = 0;
   }
  }
  else
  {
   k--;
  }
 }
 free(x);
 x = NULL;
}

利用backtracking实现(递归法)

http://www.slyar.com/blog/eight-queen-c-program.html

感觉递归掌握的还是太差了,得好好补一下!

void queens(int *x, int k, int *count, int n)
{
 for (int i = 0; i < n; i++)
 {
  x[k] = i;
  if (check(k, x) > 0)
  {  
   if (k == n - 1)
   {
    int i = 0;
    (*count)++;
    printf("\nS.%3d",(*count));
    for (i = 0; i < n; i++)
    {
     printf("%2d", x[i]);
    }
   }
   else
   {
    queens(x, k+1, count, n);
   }
  }
 }
}

利用bitwise实现

http://www.ic-net.or.jp/home/takaken/e/queen/index.html

http://www.matrix67.com/blog/archives/266

void Backtrack(int y, int left, int down, int right)
{
    int  bitmap, bit;

    if (y == SIZE) {
        COUNT++;
    } else {
        bitmap = MASK & ~(left | down | right);
        while (bitmap) {
            bit = -bitmap & bitmap;
            bitmap ^= bit;
            Backtrack(y+1, (left | bit)<<1, down | bit, (right | bit)>>1);
        }
    }
}

  
这也是一个递归过程,程序一行一行地寻找可以放皇后的地方。过程带三个参数,down、left和right,分别表示在纵列和两个对角线方向的限制条件下这一行的哪些地方不能放。我们以6x6的棋盘为例,看看程序是怎么工作的。假设现在已经递归到第四层,前三层放的子已经标在左图上了。红色、蓝色和绿色的线分别表示三个方向上有冲突的位置,位于该行上的冲突位置就用down、left和right中的1来表示。把它们三个并起来,得到该行所有的禁位,取反后就得到所有可以放的位置(用pos来表示)。前面说过-a相当于not a + 1,这里的代码第6行就相当于bitmap and (not bitmap + 1),其结果是取出最右边的那个1。这样,bit就表示该行的某个可以放子的位置,把它从bitmap中移除并递归调用test过程。注意递归调用时三个参数的变化,每个参数都加上了一个禁位,但两个对角线方向的禁位对下一行的影响需要平移一位。最后,如果递归到某个时候发现y=SIZE了,说明六个皇后全放进去了,找到的解的个数加一。

posted @ 2010-08-17 11:43  Algorithms  阅读(318)  评论(0编辑  收藏  举报