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

15 篇文章 0 订阅
7 篇文章 0 订阅

N皇后问题

8皇后问题

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

img

回溯解法

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

image-20220314144838657

剪枝:

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

image-20220314145819844

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("---------------------");
    }
}

image-20220314154541394

回溯的过程分析

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

    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皇后其中一次的过程:

image-20220314160528972

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

结构化思维wz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值