DFS算法(皇后问题解)

主要思考顺序来遍历搜索(暴力搜索)=> 递归。
在这里插入图片描述

排列数字:https://www.acwing.com/problem/content/844/

如:追溯到倒数第二个节点(A点),标记为已使用,然后再往下找,到叶子节点(标记、输出),回溯到上一节点,取消叶子的标记,然后再回溯到上一节点,取消A点的标记,当前表示 i = 2 这个节点已经遍历,接着遍历 i= 3 这个节点。

import java.io.*;
import java.util.Scanner;

public class Main{
    public static BufferedWriter log = new BufferedWriter(new OutputStreamWriter(System.out));
    public static int N = 10;
    public static int number[] = new int[N];
    public static boolean st[] = new boolean[N];
    
    public static void dfs(int u)throws IOException{
        if(u == N){
            for(int i = 0; i < N; i++)
               log.write(number[i]+" ");
            log.write("\n");
            log.flush();
        }
        
        for(int i = 1; i <= N; i++){
            if(!st[i]){
                number[u] = i;
                st[i] = true;
                dfs(u + 1);
                st[i] = false;
            }
        }
        
    }
    
    public static void main(String[] args)throws IOException{
        Scanner in = new Scanner(System.in);
        N = in.nextInt();
        dfs(0);
    }
}

皇后问题的两种解法

第一种枚举每一列,递归到下一层(下一层又去枚举每一列)。
第二种从左到右依次枚举每一个列,直到这列的末尾绕后跳到下一层首行。
第一种速度快。

import java.io.*;
import java.util.Scanner;

public class Main{
    public static int N = 20;
    public static char g[][] = new char[N][N];//存储找到的方案
    public static boolean clo[] = new boolean[N];//存储这一列是否被使用
    public static boolean dg[] = new boolean[N];//存储正对角线是否被使用
    public static boolean udg[] = new boolean[N];//存储反对角线是否被使用


    public static void dfs(int u){
        if(u == N){
            for(int i = 0; i < N; i++){
                for(int j = 0; j < N; j++)
                    System.out.print(g[i][j]);
                System.out.println();
            }
            System.out.println();
            return;
        }

        for(int i = 0; i < N; i++){
            if(!clo[i] && !dg[i + u] && !udg[i - u + N]){
                g[i][u] = 'Q';
                clo[i] = dg[i + u] = udg[i - u  + N] = true;
                dfs(u + 1);
                clo[i] = dg[i + u] = udg[i - u  + N] = false;
                g[i][u] = '.';
            }
        }

    }

    public static void main(String []args){
        Scanner in = new Scanner(System.in);

        N = in.nextInt();
        for(int i = 0; i < N; i++)
            for(int j = 0; j < N; j++)
                g[i][j] = '.';
        dfs(0);
    }
}
import java.util.Scanner;

public class Main{
    public static int N = 20;
    public static char g[][] = new char[N][N];//存储找到的方案
    public static boolean clo[] = new boolean[N];//存储这一行是否被使用
    public static boolean row[] = new boolean[N];//存储这一列是否被使用
    public static boolean dg[] = new boolean[N];//存储正对角线是否被使用
    public static boolean udg[] = new boolean[N];//存储反对角线是否被使用


    public static void dfs(int x, int y, int s){
        if(y == N){//表示列到了末尾,跳到下一行首位
            y = 0;
            x++;
        }

        if(x == N){//到达最后一行切所有皇后排列完成
           if(s == N){
                for(int i = 0; i < N; i++){
                   for(int j = 0; j < N; j++) System.out.print(g[i][j]);
                   System.out.println();
                }
                System.out.println();
           }
           return;
        }

        //不放皇后
        dfs(x, y + 1, s);

        //放皇后
        if (!row[x] && !clo[y] && !dg[x + y] && !udg[x - y + N]){
            row[x] = clo[y] = dg[x + y] = udg[x - y + N] = true;
            g[x][y] = 'Q';
            dfs(x, y + 1, s + 1);
            g[x][y] = '.';
            row[x] = clo[y] = dg[x + y] = udg[x - y + N] = false;
        }


    }

    public static void main(String []args){
        Scanner in = new Scanner(System.in);

        N = in.nextInt();
        for(int i = 0; i < N; i++)
            for(int j = 0; j < N; j++)
                g[i][j] = '.';

        dfs(0, 0, 0);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值