用栈解决N皇后问题

文章讲述了如何使用深度优先搜索算法在N×N的棋盘上放置N个皇后,避免相互攻击,并通过Java代码展示了具体步骤和逻辑。关键在于利用栈数据结构进行搜索和回溯,最终计算并输出总的解决方案数量。
摘要由CSDN通过智能技术生成

问题描述

在N×N的棋盘上摆放N个皇后,使其不能互相攻击,即任意的两个皇后不能处在同一行,同一列,或同一斜线上。请输出对于N有多少种摆放。

输入描述:

输入N,棋盘则为N×N, 棋盘上摆N个皇后。

例如:N=4, 则棋盘为4×4,棋盘上摆4个皇后.

输出描述:

输出格式为:

Total count: M

M代表对于输入N,总共有多少种摆放。

解题思路

使用栈(Stack)来模拟深度优先搜索(DFS)过程,以求解N皇后问题。

1.初始化
  • 定义一个计数器count来记录找到的总解数。
  • 定义一个栈stack来保存搜索过程中的状态。
  • 定义一个自定义的栈帧类Frame,用于保存当前棋盘状态的信息(棋盘大小n、当前正在处理的行row、以及皇后列位置数组queens)。
2.读取输入

使用Scanner读取用户输入的棋盘大小N。

3.开始搜索

初始化一个长度为N的整数数组queens,用于记录每一行皇后的列位置。

将初始状态(row = 0,queens数组为空)封装为一个Frame对象,并压入栈中。

4.栈不为空时循环

从栈中弹出一个Frame对象,即当前搜索状态。

如果当前状态对应的行号row等于棋盘大小n,说明已经成功放置了所有皇后,找到一个解,增加计数器count的值。

否则,遍历当前行的每一列col:

检查在(row, col)位置放置皇后是否安全(即是否与其他皇后冲突)。

如果安全,则在queens数组中标记该位置,并创建一个新的Frame对象(表示下一行的状态),将其压入栈中。

5.回溯

如果在当前行的所有列都尝试放置过皇后,但没有找到安全的位置,则需要回溯,即将当前行的状态撤销(即在栈中弹出当前状态),并尝试上一行的下一个位置。

6.输出解的总数

当栈为空时,表示已经搜索完所有可能的状态,此时输出找到的总解数。

Java代码实现

import java.util.Scanner;
import java.util.Stack;

public class Main
{
    // 计数器,用于记录找到的总解数
    private static int count = 0;

    // 自定义的栈帧类,用于保存状态
    static class Frame
    {
        // 棋盘的大小
        int n;
        // 当前正在处理的行
        int row;
        // 用来存储每一行皇后的列位置的数组
        int[] queens;

        // 构造函数,用于初始化栈帧
        Frame(int n, int row, int[] queens)
        {
            this.n = n;
            this.row = row;
            this.queens = queens;
        }
    }

    public static void main(String[] args)
    {
        // 读取用户输入的N值
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt())
        {
            int N = in.nextInt(); // 获取输入的N值
            int[] queens = new int[N]; // 初始化皇后的列位置数组

            // 创建一个栈来保存状态
            Stack<Frame> stack = new Stack<>();
            // 初始状态,第一行尚未放置皇后
            stack.push(new Frame(N, 0, queens));

            // 当栈不为空时,继续处理
            while (!stack.isEmpty())
            {
                Frame frame = stack.pop(); // 弹出栈顶状态

                // 如果已经处理完所有行,则找到一个解
                if (frame.row == frame.n)
                {
                    count++; // 解数加一
                }
                else
                {
                    // 遍历当前行的所有列
                    for (int col = 0; col < frame.n; col++)
                    {
                        // 检查在(row, col)位置放置皇后是否安全
                        if (isValid(frame.n, frame.queens, frame.row, col))
                        {
                            // 放置皇后
                            frame.queens[frame.row] = col;
                            // 创建新的状态(下一行),并压入栈中
                            stack.push(new Frame(frame.n, frame.row + 1, frame.queens.clone()));
                        }
                    }
                }
            }

            // 输出N皇后问题的解的总数
            System.out.println("Total count: " + count);
            count = 0; // 重置计数器以便处理下一个输入
        }

        in.close(); // 关闭输入流
    }

    // 检查在(row, col)位置放置皇后是否安全
    private static boolean isValid(int n, int[] queens, int row, int col)
    {
        // 检查列上是否有皇后互相攻击
        for (int i = 0; i < row; i++)
        {
            if (queens[i] == col)
            {
                return false;
            }
        }

        // 检查左上方对角线上是否有皇后互相攻击
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--)
        {
            if (queens[i] == j)
            {
                return false;
            }
        }

        // 检查右上方对角线上是否有皇后互相攻击
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++)
        {
            if (queens[i] == j)
            {
                return false;
            }
        }

        // 所有检查都通过,可以安全放置皇后
        return true;
    }
}
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值