• N皇后问题的递归与非递归解法


    输入一个N,找出所有在N行N列的棋盘摆放N个皇后的方法。要找出所有的解,是一个经典的使用回溯法的例子。都在注释里了:

    public class NQueen {
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            while(sc.hasNext()) {
                int N = sc.nextInt();  //假设输入的N都是合法的,这里省略了一些检查条件
                int []a = new int[N];   //a[i]表示第i行摆放的列数
                printQueenR(0,N,a);   //递归算法,从第0行开始找放置位置
                //printQueen(a,N);    //非递归就用这行
            }
            return ;
        }
    
        // (递归) 这个方法是确定第 k 行的皇后的列的位置,将列数赋给 a[k]
        public static void printQueenR(int k,int N,int []a){
    
            if(N == k) {      //如果当前行已经超过最大行了,说明某一种放置方法已经好了,输出
                for(int i = 0;i < N;i++) {
                    System.out.print(a[i] + 1 + " ");
                }
                System.out.print("
    ");
                return ;
            }
            for(int i = 0; i < N;i++) {   //第k行的第i列
                a[k] = i;                 //先将k行的列数置为i
                if(legal(k,a))            //k行的列数为i时,是否和0--(k-1)行冲突了,没有则递归调用,继续寻找k+1行的位置
                    printQueenR(k+1,N,a);
                
                //就算进入递归,结束后也继续循环,i++,再尝试k行的另一个列位置,尝试找出另一种解
            }
        }
    
        //(非递归)
        public static void printQueen(int a[],int N) {
            int t = 0;
            a[0] = -1;  //初始条件,第0行的默认列置为-1
            while(t >= 0) {  //t代表行数 ,a[t]代表第t行第a[t]列
                a[t]++;      //每循环一次,则尝试本行的下一列
                while(a[t] < N && !legal(t,a)) {  //在本t行顺序找到一个不冲突的列的位置
                    a[t]++;
                }
                if(a[t] < N) {    //如果这个列合法,即不超出棋盘
                    if (t == N - 1) {  //且目前的t行已经到头了,则输出本次放置方案
                        for (int i = 0; i < N; i++) {
                            System.out.print(a[i] + 1 + " ");
                        }
                        System.out.print("
    ");
                    }
                    else       //没到头就行数+1,准备开始下一行。由于下一行一个列都没试过,并把下一行的初始列置为-1
                        a[++t] = -1;
                }
                else {    //如果列已经试到超出棋盘了,说明t行的所有列都试过了还没有找到合适的位置,则返回下一行找另一种方案。
                    t--;  //当t<0,时执行这句话说明第0行的所有列都尝试完毕,直接退出循环
           }
    } } //公共方法。剪枝条件:检查第k行的放置的列是否合法,即是否与0--(k-1)行的放置冲突 public static boolean legal(int k,int a[]) { for (int i = 0; i < k; i++) {
            //与其他行的摆放成一列,或成斜线就不合法
    if(a[k] == a[i] || abs(k - i) == abs(a[i]-a[k])) { return false; } } return true; } }

    这里运用了一个剪枝条件大大减少了复杂度。若是蛮力破解的话复杂度是:O(N^N),因为每一行都要试N次,一共N行。剪枝后的复杂度挺难计算的,最坏是O(N!),一般是指数级的样子

  • 相关阅读:
    kubernetes架构部署
    GitLab+Jenkins+Ansible
    python之字典方法
    Python之列表方法
    python之字符串方法
    Python编写从ZabbixAPI获取信息
    Django基础
    扫描某个包下所有的类,输出所有使用了特定注解的类的注解值
    日志切面和统一异常处理
    Mybatis动态排序问题
  • 原文地址:https://www.cnblogs.com/shen-qian/p/12092171.html
Copyright © 2020-2023  润新知