• 算法——八皇后问题(eight queen puzzle)之回溯法求解


    八皇后谜题是经典的一个问题,其解法一共有92种!

    其定义:

    1. 首先定义一个8*8的棋盘
    2. 我们有八个皇后在手里,目的是把八个都放在棋盘中
    3. 位于皇后的水平和垂直方向的棋格不能有其他皇后
    4. 位于皇后的斜对角线上的棋格不能有其他皇后
    5. 解出能将八个皇后都放在棋盘中的摆法

    这个问题通常使用两种方法来求解:

    1. 穷举法
    2. 回溯法(递归)

    本文章通过回溯法来求解,回溯法对比穷举法高效许多,让我们学习如何实现吧!

    实现思想:

    1. 我们先在棋盘的第0行第1个棋格放下第一个皇后
    2. 下一行寻找一个不冲突的棋格放下下一个皇后
    3. 循环第2步
    4. 如果到某一行全部8个格子都无法放下皇后,回溯到前一行,继续寻找下一个不冲突的棋格
    5. 把8个皇后都放在棋盘之后,输出或存储摆法,结束

    实现(Java)算法:

    定义棋盘

    我们通过一个二维整型数组表示一个棋盘

    数组内为1是放下了的皇后,0则是空白的棋格

    我们下下面定义一个方法:通过检查棋格是否为1来知道是不是有皇后

    1     // 定义一个棋盘
    2     static int chessboard[][] = new int[8][8];

    检查冲突

    这个方法用来检查冲突:在水平垂直方向、斜角上的棋格有无其他皇后,传入的(x,y)是需要检查的棋格,如检查棋格(1,0)即棋盘的第2行第1个,是否能放下皇后。

     1     // 检查是否符合规则
     2     private static boolean checked(int x,int y){
     3         for(int i = 0;i<y;i++){
     4             // 检查水平垂直方向
     5             if(chessboard[x][i]==1)return false;
     6             // 检测左斜角
     7             if((x-y+i>=0)&&chessboard[x-y+i][i]==1)return false;
     8             // 检查右斜角
     9             if((x+y-i<=7)&&chessboard[x+y-i][i]==1)return false;
    10         }
    11         return true;
    12     }

    放下皇后

    我们在每一行都执行以下步骤,通过从第1个棋格到第8个遍历寻找可以放下皇后的棋格

    如果放下了皇后,我们就可以继续放下下一个了,将行数+1,我们递归调用这个方法

     1     public static boolean solve(int y){
     2         // 将一行的8种情况都扫描一次
     3         for(int i = 0;i<8;i++){
     4             // 每次检测前都将当前行清空,避免脏数据
     5             for(int k = 0;k<8;k++)chessboard[k][y]=0;
     6             if(checked(i, y)){
     7                 chessboard[i][y] = 1;
     8                 // 当前一行已经获得解法,进入下一行
     9                 solve(y+1);
    10             }
    11         }
    12         return false;
    13     }

    算法边界

    当我们放下了所有8个皇后后,需要一个终止条件,我们在行数y=8时,结束算法

    同时你可以输出一个棋盘摆法了!恭喜你已经把这个经典问题解决了!

    1         // 当y=8时,已经找到一种解决方法
    2         if(y == 8){
    3             return true;
    4         }

    以下是完整的算法

     1 public class EightQueen{
     2     // 定义一个棋盘
     3     static int chessboard[][] = new int[8][8];
     4     // 计数器
     5     static int count = 0;
     6 
     7     // 解题方法
     8     public static boolean solve(int y){
     9         // 当y=8时,已经找到一种解决方法,计数器加一并输入摆法
    10         if(y == 8){
    11             System.out.println("solved!");
    12             show();
    13             count++;
    14             return true;
    15         }
    16         // 将一行的8种情况都扫描一次
    17         for(int i = 0;i<8;i++){
    18             // 每次检测前都将当前行清空,避免脏数据
    19             for(int k = 0;k<8;k++)chessboard[k][y]=0;
    20             if(checked(i, y)){
    21                 chessboard[i][y] = 1;
    22                 // 当前一行已经获得解法,进入下一行
    23                 solve(y+1);
    24             }
    25         }
    26         return false;
    27     }
    28     // 检查是否符合规则
    29     private static boolean checked(int x,int y){
    30         for(int i = 0;i<y;i++){
    31             // 检查垂直方向
    32             if(chessboard[x][i]==1)return false;
    33             // 检测左斜角
    34             if((x-y+i>=0)&&chessboard[x-y+i][i]==1)return false;
    35             // 检查右斜角
    36             if((x+y-i<=7)&&chessboard[x+y-i][i]==1)return false;
    37         }
    38         return true;
    39     }
    40     // 输出棋盘摆法
    41     public static void show(){
    42         for(int i = 0;i<8;i++){
    43             for(int j = 0;j<8;j++){
    44                 System.out.print(chessboard[j][i]+"  ");
    45             }
    46             System.out.println("");
    47         }
    48     }
    49 }

    在执行这个算法后:

    have 92 ways to sovle it!

    我们获得了92种棋盘摆法!

     

  • 相关阅读:
    linux c++ 实现http请求
    pip 换源
    Web API接口
    DRF框架知识总览
    jq+bs插件
    element-ui插件
    axios插件
    前端存储数据汇总
    Vuex插件
    全局配置css和js
  • 原文地址:https://www.cnblogs.com/joe2047/p/10486573.html
Copyright © 2020-2023  润新知