52. N-Queens II N皇后II

本文探讨了N皇后问题的两种解决方案,一种是使用回溯法,通过递归检查每一行的皇后放置是否冲突;另一种是利用位运算,通过二进制位表示可能的皇后位置,提高效率。详细解析了每种方法的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网址:https://leetcode.com/problems/n-queens-ii/

方法1:按照逻辑思路,通过回溯法解决问题。速度较慢!

class Solution {
public:
    void backTracking(vector<string> res, int &ans, int r, int n)
    {
        bool legal = true; // 定义一个flag,用于判断某一行中的某个位置是否合法
        if(r == n) // 表示已经遍历完所有行
        {
            ans++;
            return;
        }
        for(int j = 0; j<n; j++) // 判断当前行中的每个位置
        {
            legal = true;
            for(int i = 0; i<=r-1; i++) // 判断此位置是否合法
            {
                // 分别判断 列、副对角线、主对角线
                // j - (r-i)
                if((res[i][j] == 'Q') || (res[i][j+i-r] == 'Q') || (res[i][j+r-i] == 'Q'))
                {
                    // 说明此位置会被其他皇后攻击
                    legal = false;
                    break;
                }
            }
            if(legal)
            {
                // 在此位置放置一个皇后
                res[r][j] = 'Q';
                // 将新的数据再次进行回溯
                backTracking(res, ans, r+1, n);
                // 回溯完毕后切记恢复原来的状态,以剩余的for循环
                res[r][j] = '.';
            }
        }
    }
    int totalNQueens(int n) {
        string s(n, '.');
        vector<string> vc(n, s);
        int ans = 0;
        backTracking(vc, ans, 0, n);
        return ans;
    }
};

方法2:位运算

参考:https://www.bilibili.com/video/av46292575/?p=43

class Solution {
public:
    void dfs(int &ans, int n, int row, int col, int pie, int na)
    {
        if(row == n) // 表示已经遍历完所有行
        {
            ans++;
            return;
        }
        // 把int类型的col、pie、na以二进制来看待,0分别表示此格子不会被其他皇后以某种方式攻击,1表示会
        // (col|pie|na)得到总的攻击情况,但我们需要的是当中 0 的位置,因为0的位置无法获取,所以
        // 对(col|pie|na)取反,即'~'操作符。取反后,数据的后n位是满足我们的要求的
        // 但是,前面原来的0都变成了1,所以要想办法把第n位之前的0还原为1
        // (1 << n)-1) 即可产生000...001111这样一个数,将其&上原来的数,即可实现预想
        int bits = ((~(col|pie|na))&((1 << n)-1));
        while(bits) //
        {
            int pos = bits & -bits; // 得到一个只保留最后一位 1 ,其他的全为 0 的数
            // 更新数据,注意对角线的挪移
            dfs(ans, n, row+1, col|pos, (pie|pos)<<1, (na|pos)>>1);
            // 把bits去掉最后一位的 1
            bits = bits & (bits-1);
        }
    }
    int totalNQueens(int n) {
        int ans = 0;
        dfs(ans, n, 0, 0, 0, 0);
        return ans;
    }
};

 

转载于:https://www.cnblogs.com/tornado549/p/10701124.html

1. 用户与权限管理模块 角色管理: 学生:查看实验室信息、预约设备、提交耗材申请、参与安全考核 教师:管理课题组预约、审批学生耗材申请、查看本课题组使用记录 管理员:设备全生命周期管理、审核预约、耗材采购与分发、安全检查 用户操作: 登录认证:统一身份认证(对接学号 / 工号系统,模拟实现),支持密码重置 信息管理:学生 / 教师维护个人信息(联系方式、所属院系),管理员管理所有用户 权限控制:不同角色仅可见对应功能(如学生不可删除设备信息) 2. 实验室与设备管理模块 实验室信息管理: 基础信息:实验室编号、名称、位置、容纳人数、开放时间、负责人 功能分类:按学科(计算机实验室 / 电子实验室 / 化学实验室)标记,关联可开展实验类型 状态展示:实时显示当前使用人数、设备运行状态(正常 / 故障) 设备管理: 设备档案:名称、型号、规格、购置日期、单价、生产厂家、存放位置、责任人 全生命周期管理: 入库登记:管理员录入新设备信息,生成唯一资产编号 维护记录:记录维修、校准、保养信息(时间、内容、执行人) 报废处理:登记报废原因、时间,更新设备状态为 "已报废" 设备查询:支持按名称、型号、状态多条件检索,显示设备当前可用情况 3. 预约与使用模块 预约管理: 预约规则:学生可预约未来 7 天内的设备 / 实验室,单次最长 4 小时(可设置) 预约流程:选择实验室→选择设备→选择时间段→提交申请(需填写实验目的) 审核机制:普通实验自动通过,高危实验(如化学实验)需教师审核 使用记录: 签到 / 签退:到达实验室后扫码签到,离开时签退,系统自动记录实际使用时长 使用登记:填写实验内容、设备运行情况(正常 / 异常),异常情况需详细描述 违规管理:迟到 15 分钟自动取消预约,多次违规限制预约权限 4. 耗材与安全管理模块 耗材管理: 耗材档案:名称、规格、数量、存放位置、
<think>好的,用户想要获取N皇后问题的Java实现代码,并完善place和queen方法。首先,我需要回忆一下N皇后问题的基本要求和解决方法。N皇后问题是在一个N×N的棋盘上放置N个皇后,使得它们互不攻击,即任何两个皇后都不能处于同一行、同一列或同一对角线上。 根据用户提供的引用内容,特别是引用[3]中的C代码,可以看到使用回溯法来解决这个问题。回溯法的基本思路是逐行放置皇后,并在每行中尝试不同的列,同时检查当前位置是否安全。如果安全,则继续下一行;如果不安全,则回溯到上一行,尝试下一个列位置。 用户提到需要Java实现,并完善place和queen方法。首先,我需要确定这两个方法的功能。place方法应该负责检查当前位置是否安全,即是否与之前放置的皇后冲突。queen方法可能是回溯的主体,负责递归地在每一行放置皇后。 接下来,我需要将引用[3]中的C代码转换为Java。需要注意Java的语法差异,例如数组的索引、方法的定义等。在C代码中,数组索引从1开始,但Java中通常从0开始,这可能需要调整。另外,Java中没有指针,因此数组需要作为参数传递。 在place方法中,C代码遍历之前的所有行,检查列冲突和对角线冲突。Java实现也需要类似逻辑,但要注意数组索引的正确性。例如,当前行paraT在C代码中从1开始,而Java可能需要从0开始,这会影响循环条件。 对于queen方法(在Java中可能是backtracking方法),需要递归地尝试每一列,并调用place方法检查安全性。如果安全,则继续下一行;否则回溯。此外,需要记录解决方案,比如存储每个皇后所在的列位置,并在找到所有解时计数或输出。 用户还提到要完善这两个方法,可能需要考虑代码的可读性和效率。例如,使用一维数组存储皇后的位置,其中数组的索引表示行号,值表示列号。这样可以简化检查冲突的逻辑。 另外,需要考虑Java中输出结果的方式。用户可能需要返回所有解的列表,或者仅计数解的数量。根据引用[1]中的题解,N皇后II只需要计数,但用户可能想要具体解的展示,因此需要确认需求。不过用户的问题中并没有明确说明,但之前的引用[3]中的代码输出具体解,因此可能需要在Java实现中输出所有解的皇后位置。 在检查冲突时,除了列冲突,还需要检查主对角线和副对角线。主对角线上的行差等于列差,副对角线上的行差等于负的列差。例如,对于两个位置(row1, col1)(row2, col2),如果row1 - row2 == col1 - col2,则在同一主对角线;如果row1 - row2 == -(col1 - col2),则在副对角线。 现在,开始编写Java代码。定义一个类NQueens,包含一个place方法,检查当前位置是否安全,以及一个solve方法(或queen方法)进行回溯。使用一个数组queens[],其中queens[i]表示第i行皇后所在的列。从第0行开始,逐行放置皇后,尝试每一列,并调用place方法检查。如果安全,则递归处理下一行,直到所有行处理完毕,记录一个解。 在实现place方法时,需要遍历之前所有已放置的行,检查列是否相同或对角线冲突。例如,对于当前行row,遍历0到row-1的每一行i,检查queens[i] == queens[row](列冲突),或者Math.abs(row - i) == Math.abs(queens[row] - queens[i])(对角线冲突)。 在solve方法中,使用回溯递归。当当前行等于n时,表示找到一个解,将其加入结果列表。否则,遍历所有可能的列,放置皇后,检查安全性,递归处理下一行,然后回溯。 此外,用户可能需要将解以某种格式输出,例如List<List<String>>,每个解表示为一个棋盘的字符串列表。或者,如果只是计数,可以维护一个计数器。根据引用[1]中的题解,52题是N皇后II,只需要计数,但用户的问题可能更接近引用[3]的输出具体解的情况,因此需要同时考虑两种可能性。但用户明确要求完善place和queen方法,可能更关注具体解的生成。 最后,测试代码的正确性,例如对于n=4,应有两个解,确保程序正确输出。同时,优化代码结构,确保变量命名清晰,注释充分,便于用户理解。</think>### Java版N皇后问题实现(回溯法) #### 完整代码实现 ```java import java.util.ArrayList; import java.util.List; public class NQueens { private List<List<String>> solutions = new ArrayList<>(); private int[] queens; // queens[row] = 列索引 public List<List<String>> solveNQueens(int n) { queens = new int[n]; backtrack(0, n); return solutions; } // 检查第row行是否能放置在queen[row]列 private boolean isPlaceValid(int row) { for (int i = 0; i < row; i++) { // 列冲突检查 | 主对角线检查 | 副对角线检查 if (queens[i] == queens[row] || Math.abs(row - i) == Math.abs(queens[row] - queens[i])) { return false; } } return true; } // 回溯核心方法 private void backtrack(int currentRow, int totalQueens) { if (currentRow == totalQueens) { generateSolution(totalQueens); return; } for (int col = 0; col < totalQueens; col++) { queens[currentRow] = col; // 尝试放置 if (isPlaceValid(currentRow)) { backtrack(currentRow + 1, totalQueens); // 递归下一行 } } } // 将皇后位置转换为棋盘字符串 private void generateSolution(int n) { List<String> board = new ArrayList<>(); for (int row = 0; row < n; row++) { StringBuilder sb = new StringBuilder(); for (int col = 0; col < n; col++) { sb.append(queens[row] == col ? "Q" : "."); } board.add(sb.toString()); } solutions.add(board); } public static void main(String[] args) { NQueens solver = new NQueens(); List<List<String>> results = solver.solveNQueens(4); System.out.println("Total solutions: " + results.size()); for (List<String> solution : results) { System.out.println("----- Solution -----"); solution.forEach(System.out::println); } } } ``` #### 关键方法说明 1. **isPlaceValid()** - 功能:验证当前行皇后位置是否合法 - 检查规则: - 列冲突:`queens[i] == queens[row]` - 对角线冲突:`|row - i| == |queens[row] - queens[i]|` - 时间复杂度:$O(n)$,其中n为当前行数 2. **backtrack()** - 递归终止条件:`currentRow == totalQueens`(成功放置所有皇后- 遍历当前行所有列,尝试放置后验证合法性 - 时间复杂度:$O(n!)$,最坏情况下需要遍历所有可能性 #### 执行结果示例(n=4) ``` Total solutions: 2 ----- Solution ----- .Q.. ...Q Q... ..Q. ----- Solution ----- ..Q. Q... ...Q .Q.. ``` #### 优化方向 1. **位运算加速** 使用位掩码代替数组存储,可将时间复杂度降为$O(n!)$但常数项更小[^1] 2. **对称性剪枝** 利用棋盘对称性减少重复计算,如镜像对称、旋转对称等 3. **并行计算** 将不同起始位置的搜索任务分配到多线程执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值