zoukankan      html  css  js  c++  java
  • 算法:N-皇后问题

    一、八皇后问题

      八皇后问题是一个以国际象棋为背景的问题:如何能够在8 × 8 的国际象棋棋盘上放置八个皇后Queen),使得任何一个皇后都无法直接吃掉其他的皇后。为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的N皇后摆放问题:这时棋盘的大小变为 N ×N,而皇后个数也变成 N当且仅当 n = 1 或 n ≥ 4 时问题有解。

    二、利用回溯法递归求解N-皇后问题

      生成棋盘所有皇后摆放的可能配置,并打印满足给定约束的配置。回溯算法的思想是将皇后从最左边的列开始一一放置在不同的列中。 当我们将皇后放在一列中时,检查是否与已经放置的皇后发生冲突。 在当前列中,如果找到没有冲突的行,则将该行和列标记为解决方案的一部分。 如果由于冲突而找不到这样的行,那么我们将回溯并返回 false

      首先是从棋盘最左边的列开始摆放皇后。

    算法主要内容:

    1. 当 col = N 时,所有皇后摆放完毕,问题有解

    2. 算法从每一列的每一行来推进问题的求解:

    • a) 如果该位置 (i, j) 能把皇后无冲突的放进去,标记这个位置为 1,然后一直递归求解下一列的某行位置能否求解问题;
    • b) 如果这个位置能摆放皇后则返回 true;
    • c) 如果放置皇后并不能解决问题,取消标记此 (i, j)(回溯),然后转到步骤(a)尝试其他行。

    3. 如果所有列所有行都尝试探索过后依然无解,返回 false(回溯)。

    三、N-皇后问题的实现

      检查当前位置放置皇后会与之前放置的皇后冲突。这里的时间复杂度为 O(N)。

     1     /**
     2      * 用于检查是否可以将Queen放在当前位置上
     3      *
     4      * @param board
     5      * @param row
     6      * @param col
     7      * @return
     8      */
     9     private boolean isSafe(int[][] board, int row, int col) {
    10         int i, j;
    11 
    12         /* 是否在同一行(左侧) */
    13         for (i = 0; i < col; i++)
    14             if (board[row][i] == 1)
    15                 return false;
    16 
    17             /* 是否在反对角线方向上 */
    18             for (i = row, j = col; i >= 0 && j >= 0; i--, j--)
    19                 if (board[i][j] == 1)
    20                     return false;
    21 
    22                 /* 是否在对角线方向上 */
    23                 for (i = row, j = col; j >= 0 && i < N; i++, j--)
    24                     if (board[i][j] == 1)
    25                         return false;
    26 
    27         return true;
    28     }

      通过递归方式来探索问题的解,在所有位置尝试完之前,探索问题的解失败时通过回溯来寻找下一个皇后的摆放位置,回溯同时把摆放位置的标记复原。对于N皇后的时间复杂度,分析起来有点复杂,但从中可以分析其时间复杂度为 O(N3)。

     1     /**
     2      * 递归求解N-Queen问题
     3      *
     4      * @param board
     5      * @param col
     6      * @return
     7      */
     8     private boolean solveNQUtils(int[][] board, int col) {
     9         /* 如果所有皇后都被放置, 然后返回true */
    10         if (col >= N)
    11             return true;
    12 
    13         /* 考虑当前col能否摆放Queen */
    14         for (int i = 0; i < N; i++) {
    15             /* 当前位置是否能摆放Queen */
    16             if (isSafe(board, i, col)) {
    17                 board[i][col] = 1;
    18 
    19                 /* 再次摆放Queen, 如果成功直接返回true */
    20                 if (solveNQUtils(board, col + 1)) {
    21                     return true;
    22                 }
    23 
    24                 /* 这是在某列无法放Queen回溯时把queen移走 */
    25                 board[i][col] = 0;
    26             }
    27         }
    28 
    29         return false;
    30     }

    本文源代码:

      1 package algorithm;
      2 
      3 /**
      4  * N皇后问题,回溯法,简单分析一下,时间复杂度大概为 O(N^3)
      5  */
      6 public class NQueenProblem {
      7     private final int N = 8;
      8 
      9     /**
     10      * 打印符合条件的摆放棋盘
     11      *
     12      * @param board
     13      */
     14     private void printSolution(int[][] board) {
     15         for (int i = 0; i < N; i++) {
     16             for (int j = 0; j < N; j++) {
     17                 System.out.print(" " + board[i][j] + " ");
     18             }
     19             System.out.println();
     20         }
     21     }
     22 
     23     /**
     24      * 用于检查是否可以将Queen放在当前位置上
     25      *
     26      * @param board
     27      * @param row
     28      * @param col
     29      * @return
     30      */
     31     private boolean isSafe(int[][] board, int row, int col) {
     32         int i, j;
     33 
     34         /* 是否在同一行(左侧) */
     35         for (i = 0; i < col; i++)
     36             if (board[row][i] == 1)
     37                 return false;
     38 
     39             /* 是否在反对角线方向上 */
     40             for (i = row, j = col; i >= 0 && j >= 0; i--, j--)
     41                 if (board[i][j] == 1)
     42                     return false;
     43 
     44                 /* 是否在对角线方向上 */
     45                 for (i = row, j = col; j >= 0 && i < N; i++, j--)
     46                     if (board[i][j] == 1)
     47                         return false;
     48 
     49         return true;
     50     }
     51 
     52     /**
     53      * 递归求解N-Queen问题
     54      *
     55      * @param board
     56      * @param col
     57      * @return
     58      */
     59     private boolean solveNQUtils(int[][] board, int col) {
     60         /* 如果所有皇后都被放置, 然后返回true */
     61         if (col >= N)
     62             return true;
     63 
     64         /* 考虑当前col能否摆放Queen */
     65         for (int i = 0; i < N; i++) {
     66             /* 当前位置是否能摆放Queen */
     67             if (isSafe(board, i, col)) {
     68                 board[i][col] = 1;
     69 
     70                 /* 再次摆放Queen, 如果成功直接返回true */
     71                 if (solveNQUtils(board, col + 1)) {
     72                     return true;
     73                 }
     74 
     75                 /* 这是在某列无法放Queen回溯时把queen移走 */
     76                 board[i][col] = 0;
     77             }
     78         }
     79 
     80         return false;
     81     }
     82 
     83     /**
     84      * 解决并打印N-Queen的问题
     85      *
     86      * @return
     87      */
     88     private boolean solveNQ() {
     89         int[][] board = new int[N][N];
     90 
     91         if (!solveNQUtils(board, 0)) {
     92             System.out.println("Solution does not exist");
     93             return false;
     94         }
     95 
     96         printSolution(board);
     97         return true;
     98     }
     99 
    100     public static void main(String[] args) {
    101         NQueenProblem queen = new NQueenProblem();
    102         queen.solveNQ();
    103     }
    104 }
    View Code
  • 相关阅读:
    div在父集高度未知的情况下垂直居中的方法
    固比固布局 圣杯布局 css实现传统手机app布局
    img标签的onerror事件
    vue中的swiper element ui
    前后端分离跨域 关于前后端分离开发环境下的跨域访问问题(angular proxy=>nginx )
    自己开发的网页在跳转至微信公众号文章后,点击微信的返回,无法返回原网页
    关于audio元素在实际项目中遇到的问题总结
    移动端HTML5<video>视频播放优化实践
    数据类型转换
    穿越宇宙的邀请函——镜像图片技巧
  • 原文地址:https://www.cnblogs.com/magic-sea/p/12093756.html
Copyright © 2011-2022 走看看