zoukankan      html  css  js  c++  java
  • N皇后问题----回溯法

    N皇后问题描述为:如何能够在 n*n  的国际象棋棋盘上放置 n 个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。

    比如经典的8皇后问题的一个解:

                                        

    一开始你也许会像我一样,想到用一个二维数组来实现,并且用线面描述的算法:

    用一个N*N的矩阵来存储棋盘:

          1) 算法开始, 清空棋盘,当前行设为第一行,当前列设为第一列

          2) 在当前行,当前列的位置上判断是否满足条件(即保证经过这一点的行,列与斜线上都没有两个皇后),若不满足,跳到第4步

          3) 在当前位置上满足条件的情形:

                     在当前位置放一个皇后,若当前行是最后一行,记录一个解;

                     若当前行不是最后一行,当前行设为下一行, 当前列设为当前行的第一个待测位置;

                     若当前行是最后一行,当前列不是最后一列,当前列设为下一列;

                     若当前行是最后一行,当前列是最后一列,回溯,即清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一个待测位置;

                    以上返回到第2步

          4) 在当前位置上不满足条件的情形:

                    若当前列不是最后一列,当前列设为下一列,返回到第2步;

                    若当前列是最后一列了,回溯,即,若当前行已经是第一行了,算法退出,否则,清空当前行及以下各行的棋盘,然后,当前行设为上一行,当前列设为当前行的下一    个待测位置,返回到第2步; 

    当然,实际上我们的思路就该如此,但真的用这样一个二维数组去实现的话会发生什么事情?我们需要在每一个递归中遍历同行,同列, 两条对角线,那么我们要调用多少次的判断函数?并且当N的数值很大的时候,二维数组很明显是低效的。那么我们应该如何去实现呢?

    首先,我们已经知道不可能有两个皇后在同一行,又一共有 n 个皇后,所以每行有且只有一位皇后。另外,同理我们可以知道每列有且只有一位皇后。

    有了这个前提,那么我们就可以直接用一个有 n 大小的一位数组来储存了,每个元素用来储存列号,如图:                                                                                                                                                         

    OK,现在我们有了一种较为轻便的储存方式,剩下的就是怎么得到一个有效的八皇后序列问题了。我们都知道回溯法,这个是遍历所有可能情况以得到满足条件的序列,那么我们就可以遍历所有的可能序列判断满不满足,而得到全部的序列的方法就可以根据我们的储存结构的特点,也即一位数组,来得到全排列,然后判断每一个全排列满不满足条件。。。全排列可以看看我前面的关于全排列的博文。。。

    那么我们应该怎么判断一个全排列是不是满足条件呢?因为我们的储存结构的特点,各行列上都只有一个皇后了,那么久只需要判断对角线了,我们来看看一个8*8的棋盘:

                           

    格子 [3 3] 和格子 [2 4] 我们可以发现 |3 - 2| == |3 - 4|,对 [3 5] 和 [4 4] 我们同样有 |3 - 4| == |5 - 4|,其他在同一对角线的元素都具有相同的性质,也就是说,在同一对角线上的元素会具有性质 |col_1 - col_2| == |row_1 - row_2|, 那么我们要判断两皇后是否在同一对角线,就只需要比较他们的行列值得对应差的绝对值了。

    好了,到这里我们基本就可以得到N皇后问题的全部可能情况了,下面是实现的代码:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <cmath>
     4 
     5 using namespace std;
     6 
     7 int count_;
     8 
     9 void output(int* queenArray, int numberOfQueen) {
    10     printf("|--------------------------------
    |");
    11     for (int i = 0; i != numberOfQueen; i++) {
    12         for (int j = 0; j != numberOfQueen; j++) {
    13             if (j == queenArray[i])
    14                 printf(" $ |");
    15             else
    16                 printf(" * |");
    17         }
    18         printf("
    |");
    19     }
    20     printf("--------------------------------
    ");
    21 }
    22 
    23 void swap(int& a, int& b) {
    24     int temp = a;
    25     a = b;
    26     b = temp;
    27 }
    28 
    29 bool queenValuid(int* queenArray, int len) {
    30     //判断某序列是否有两个皇后在同一对角线
    31     for (int i = 0; i != len; i++) {
    32         for (int j = i + 1; j != len; j++) {
    33             if (abs(j - i) == abs(queenArray[j] - queenArray[i]))
    34                 return false;
    35         }
    36     }
    37     return true;
    38 }
    39 
    40 void queen(int* queenArray, int begin, int end) {
    41     if (begin == end) {
    42         if (queenValuid(queenArray, end + 1)) {
    43             count_++;
    44             output(queenArray, end + 1);
    45         }
    46     } else {
    47         //全排列
    48         for (int i = begin; i <= end; i++) {
    49             swap(queenArray[begin], queenArray[i]);
    50             queen(queenArray, begin + 1, end);
    51             swap(queenArray[begin], queenArray[i]);
    52         }
    53     }
    54 }
    55 
    56 int main(int argc, char const *argv[])
    57 {
    58     char command;
    59     int *queenArray;
    60     int numberOfQueen;
    61     do {
    62         int start = clock();
    63         {
    64             count_ = 0;
    65             printf("Enter the number of the queen: ");
    66             scanf ("%d", &numberOfQueen);
    67 
    68             queenArray = new int[numberOfQueen];
    69             for (int i = 0; i != numberOfQueen; i++)
    70                 queenArray[i] = i;
    71 
    72             queen(queenArray, 0, numberOfQueen - 1);
    73             printf("Total queen seq: %d
    ", count_);
    74 
    75             delete []queenArray;
    76         }
    77         printf("
    run time: %.3lf ms
    ",double(clock()-start)/CLOCKS_PER_SEC);
    78 
    79         printf("Again?<Y/N>
    ");
    80         scanf("
    %c", &command);
    81     } while (command == 'Y' || command == 'y');
    82     
    83     return 0;
    84 }
  • 相关阅读:
    多态
    抽象类和接口
    面向对象3
    类的继承 设计模式
    面向对象2
    面向对象
    复习
    对json的简单认识
    关于AJAX
    PHP配置开发环境
  • 原文地址:https://www.cnblogs.com/xiezhw3/p/3450137.html
Copyright © 2011-2022 走看看