恋上数据结构回溯 | N皇后问题

Posted 结构化思维wz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了恋上数据结构回溯 | N皇后问题相关的知识,希望对你有一定的参考价值。

N皇后问题

8皇后问题

❓ 在 8*8 的棋盘上,摆放八个皇后,使其不能互相攻击:任意两个皇后不能处于同一行、列、对角线上。 问有多少种摆法?

回溯解法

首先,缩小问题范围(4皇后问题),理解回溯的思想:

剪枝:

根据限制条件,发现同一行同一列、对角线不能摆放皇后,可以进行剪枝操作。

package 回溯;

/**
 * @ClassName: Quen
 * @Description: 八皇后问题
 * @author: WangZe
 * @date: 2022/3/14 14:40
 */
public class Queens
    public static void main(String[] args) 
       new Queens().placeQueens(8);
    

    /**
     * 数组索引是行号,数组元素是列号,用来记录皇后的位置
     */
    int[] cols;
    /**
     * 有多少中摆法
     */
    int ways;

    /**
     * 思路:回溯+剪枝
     * @param queenCount 皇后数量
     */
    public void placeQueens(int queenCount)
        if(queenCount < 1)return;
        cols = new int[queenCount];
        //从第0行开始摆放
        place(0);
        System.out.println(ways);

    

    /**
     * 从第row行开始摆放皇后
     * @param row 行
     */
    public void place(int row)
        //如果到row==n 说明已经摆完了
        if(row == cols.length)
            ways++;
            return;
        
        for (int col = 0; col < cols.length; col++) 
            //如果位置能摆放皇后
            if(isValid(row,col))
                //在第row行,第col列摆放皇后
                cols[row] = col;
                //摆放好后,开始下一行
                place(row+1);
            
        
    

    /**
     * 剪枝函数,判断第row行,第col列是否合法
     * @param row
     * @param col
     * @return
     */
    public boolean isValid(int row,int col)
        for (int i = 0; i < row; i++) 
            //列有皇后
            if(cols[i] == col)
                return false;
            
            //斜线有皇后
            //(row - i)/(col-cols[i]) == 1 or -1;斜率为1or-1,代表处于同一斜线
            if(row - i == Math.abs(col - cols[i]))
                return false;
            

        
        return true;
    


如何显示具体摆放位置呢???

package 回溯;

/**
 * @ClassName: Quen
 * @Description: 八皇后问题
 * @author: WangZe
 * @date: 2022/3/14 14:40
 */
public class Queens
    public static void main(String[] args) 
       new Queens().placeQueens(4);
    

    /**
     * 数组索引是行号,数组元素是列号,用来记录皇后的位置
     */
    int[] cols;
    /**
     * 有多少中摆法
     */
    int ways;

    /**
     * 思路:回溯+剪枝
     * @param queenCount 皇后数量
     */
    public void placeQueens(int queenCount)
        if(queenCount < 1)return;
        cols = new int[queenCount];
        //从第0行开始摆放
        place(0);
        System.out.println(queenCount+"皇后的摆放有几种摆法? "+ways);

    

    /**
     * 从第row行开始摆放皇后
     * @param row 行
     */
    public void place(int row)
        //如果到row==n 说明已经摆完了
        if(row == cols.length)
            ways++;
            show();
            return;
        
        for (int col = 0; col < cols.length; col++) 
            //如果位置能摆放皇后
            if(isValid(row,col))
                //在第row行,第col列摆放皇后
                cols[row] = col;
                //摆放好后,开始下一行
                place(row+1);
            
        
    

    /**
     * 剪枝函数,判断第row行,第col列是否合法
     * @param row
     * @param col
     * @return
     */
    public boolean isValid(int row,int col)
        for (int i = 0; i < row; i++) 
            //列有皇后
            if(cols[i] == col)
                return false;
            
            //斜线有皇后
            //(row - i)/(col-cols[i]) == 1 or -1;斜率为1or-1,代表处于同一斜线
            if(row - i == Math.abs(col - cols[i]))
                return false;
            

        
        return true;
    

    /**
     * 打印摆法
     */
    public void show()
        for (int row = 0; row < cols.length; row++) 
            for (int col = 0; col < cols.length; col++) 
                if(cols[row] == col)
                    System.out.print("1 ");
                else 
                    System.out.print("0 ");
                
            
            System.out.println();
        
        System.out.println("---------------------");
    


回溯的过程分析

在剪枝方法中,添加打印语句,观察整个回溯过程:

    public boolean isValid(int row,int col)
        for (int i = 0; i < row; i++) 
            //列有皇后
            if(cols[i] == col)
                System.out.println("["+row+"] ["+col+"] = false");
                return false;
            
            //斜线有皇后
            //(row - i)/(col-cols[i]) == 1 or -1;斜率为1or-1,代表处于同一斜线
            if(row - i == Math.abs(col - cols[i]))
                System.out.println("["+row+"] ["+col+"] = false");
                return false;
            
        
        System.out.println("["+row+"] ["+col+"] = true");
        return true;
    

4皇后其中一次的过程:

以上是关于恋上数据结构回溯 | N皇后问题的主要内容,如果未能解决你的问题,请参考以下文章

8皇后问题--回溯法 (循环递归)

求教C语言回溯法写出八皇后问题的92种解

N皇后 八皇后 位运算解法

回溯算法之N皇后问题

八皇后解法(回溯法)

回溯法解决四皇后问题