递归和回溯经典题目--n皇后问题

本文探讨了递归与回溯在解决经典算法问题中的应用,以n皇后问题为例。通过理解如何判断列和对角线上的冲突,可以实现Java代码来解决这个问题。递归和回溯的思想在BFS和DFS等算法中同样关键。
摘要由CSDN通过智能技术生成

      递归和回溯密不可分,可以把递归的过程就是回溯的过程。其中BFS,DFS等经典问题都是与递归和回溯的思想紧密相关的。我们可以不用纠结于每个问题的标签,只要能运用相关的思想解决问题即可。下边,来讨论一下回溯和递归的经典算法问题:n皇后问题。

问题描述:



我们可以把此问题看成递归图:



  此题关键是:如何判断冲突。也就是列,对角冲突







Java实现的代码如下:


package com.algorithm;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description: n皇后问题
 * @author: Jingzeng Wang
 * @Date: Created in 18:41  2017/12/13.
 */
public class NQueen {

    // 保存全部结果
    static List<List<String>> reslut = new ArrayList<>();

    // 下边的集合完全可以用数组来替代,如果知道n的话。将n放在外部即可。

    // 保存列是否冲突. 若i列放置了就置其为true
    static List<Boolean> col = new ArrayList<>();
    // 保存对角是否冲突 规律  行+列  0 -- (n-1) 用来判断对角线是否有冲突
    static List<Boolean> dia1 = new ArrayList<>();
    // 保存对角是否冲突 规律  列-行  -(n-1) -- (n-1) 用来判断对角线是否有冲突
    static List<Boolean> dia2 = new ArrayList<>();

    public static void main(String[] args) {
        // n皇后
        int n = 11;
        // 初始化集合
        for (int i = 0; i < n; i++) {
            col.add(false);
        }
        // 对角线数 2*n-1
        for (int i = 0; i < 2 * n - 1; i++) {
            dia1.add(false);
            dia2.add(false);
        }

        // 保存每次的结果
        List<Integer> res = new ArrayList<>();

        generateQueen(n, 0, res);

        printResult(n);
    }

    /**
     * 递归回溯求解n皇后
     *
     * @param n     n皇后
     * @param index 第index行
     * @param res   保存一次搜索结果
     */
    private static void generateQueen(int n, int index, List res) {
        if (index == n) {
            reslut.add(formatResult(n, res));
            return;
        }

        // 遍历每一列可放置的位置
        for (int i = 0; i < n; i++) {
            // 判断列,对角线,是否可进行放置
            if (!col.get(i) && !dia1.get(i + index) && !dia2.get(index - i + n - 1)) {
                res.add(i);
                col.set(i, true);
                dia1.set(i + index, true);
                dia2.set(index - i + n - 1, true);
                // 递归寻找下一行
                generateQueen(n, index + 1, res);
                // 遍历完i列的可能结果后,回溯状态,继续下一列
                col.set(i, false);
                dia1.set(i + index, false);
                dia2.set(index - i + n - 1, false);
                res.remove(res.size() - 1);
            }
        }
        return;
    }

    /**
     * 格式化结果
     *
     * @param n
     * @param res
     * @return
     */
    private static List<String> formatResult(int n, List res) {
        List<String> list = new ArrayList<>();

        for (int i = 0; i < n; i++) {
            StringBuffer sb = new StringBuffer();
            for (int j = 0; j < n; j++) {
                if ((int) res.get(i) == j) {
                    sb.append("Q ");
                    continue;
                }
                sb.append(". ");
            }
            list.add(sb.toString());
        }
        return list;
    }

    /**
     * 打印结果
     *
     * @param n
     */
    private static void printResult(int n) {
        int count = 1;
        for (List<String> singleRes : reslut) {
            System.out.println(count++);
            for (String s : singleRes) {
                System.out.println(s);
            }
            System.out.println();
        }
        System.out.println(n + "皇后问题,共" + (count - 1) + "种结果!");
    }
}


















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值