算法-DFS(基础)-全排列、n皇后问题

引入:从今天开始,我们来进行搜索与图论的学习。首先是搜索,分成DFS和BFS,今天主要讲DFS基础。

两种搜索的区别和联系

联系:

  • BFS和DFS都可以对整个空间进行遍历
  • 结构都像一棵树一样进行搜索

区别:

  • DFS:每一步都往深搜,当搜到叶子节点就进行回溯
  • BFS:一层一层进行搜索,每一层搜完再搜索下一层
    在这里插入图片描述

如何入手:

  • DFS:回溯剪枝
  • 每个DFS都对应一条搜索树,最重要要考虑顺序进行遍历所有方案

什么是DFS

dfs是一种搜索方式——深度优先搜索,属于图算法的一种,所以DFS都可以建成树的形式进行遍历。主要涉及到递归

全排列:

思路(DFS详解):

一共有n个位置,从第一个位置开始考虑,思考当前位置可以填哪些数字,a数字在当前组成的顺序中被用过后,就打上标记,当前顺序后面组成的数字将不使用a,保证当前顺序组成的数字中,每个数字只出现一次进行排列。当这条路走完之后,到达叶子节点(第一种组成顺序完成后),回溯到上一个节点,看有没有别的方式往下走,这样一步步走+回溯直到完成。

回溯到上一个节点,看有没有别的方式往下走——>实现办法:把走过的数字做上标记,一条路径走完后,回到上一个节点时,要把原本的点恢复原样

需要什么

1.需要一个int型的path数组,来存已经确定位置填的值(每一条路径的答案)
2.需要一个boolean型的st数组,来存当前路径已经有哪些数填过了,以此来判断往下走还有哪些数能填

题目-全排列

在这里插入图片描述

详解(Java)

import java.util.Scanner;

public class DFS {
    static int n = 10;
    static int[] path = new int[n];//已经确定位置填的数字
    static boolean[] st = new boolean[n];//存当前路径已经填过的数,以此判断接下来哪些数能填

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        dfs(0);
    }

    public static void dfs(int u){//遍历顺序:从第一个位置开始看填数字,再到第二个位置...n个位置表明当前路径位置已全部填完
        if(u==n){
            for (int i = 0; i < n; i++) {
                System.out.print(path[i]+" ");
            }
            System.out.println();
          return;
        }
        for (int i = 1; i <= n; i++) {
            if(!st[i]){//当前数字没有用过,可以填
                path[u] = i;//第u个位置放的数字
                st[i] = true;//记录放过的数字
                dfs(u+1);//递归到下一个位置
                st[i] = false;//恢复原状,重新进行排序:递归一层结束后,回到上一层——>回溯,恢复数字未使用原样,重新排序
            }
        }
    }
}

题目-n皇后

在这里插入图片描述
在这里插入图片描述

详解方法一:枚举(Java)

思路:以行为搜索顺序,一行一行进行判断,条件都满足再放 ,否则就不放

import java.util.Scanner;

public class N皇后 {
    static int n = 20;
    static char[][] path = new char[n][n];
    static boolean[] col = new boolean[n];//列
    static boolean[] dg = new boolean[n];//对角线
    static boolean[] udg = new boolean[n];//反对角线

    //u行
    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(path[i][j]);
                }
                System.out.println();
            }
            System.out.println();
            return;
        }else {
            for (int i = 0; i < n; i++) {
                if((!col[i]) && (!dg[u + i]) && (!udg[n - u + i])){
                    path[u][i] = 'Q';
                    col[i] = dg[u + i] = udg[n - u + i] = true;
                    dfs(u + 1);
                    col[i] = dg[u + i] = udg[n - u + i] = false;
                    path[u][i] = '.';
                }
            }
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        n = input.nextInt();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                path[i][j] = '.';
            }
        }
        dfs(0);
    }
}

详解方法一:每个格子进行选择(Java)

思路:每个格子进行条件选择,放或者不放皇后,进行搜索

import java.util.Scanner;

public class Main {
    static int n = 20;
    static char[][] path = new char[n][n];
    static boolean[] row = new boolean[n];//行
    static boolean[] col = new boolean[n];//列
    static boolean[] dg = new boolean[n];//对角线
    static boolean[] udg = new boolean[n];//反对角线

    //x行,y列,s皇后数量
    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(path[i][j]);
                    }
                    System.out.println();
                }
                System.out.println();
            }
            return;
        }
        //不放皇后
        dfs(x,y + 1,s);
        //放皇后
        if((!row[x]) && (!col[y]) && (!dg[n + y - x]) && (!udg[y + x])){
            path[x][y] = 'Q';
            row[x] = col[y] = dg[n + y - x] = udg[x + y] = true;
            dfs(x,y + 1,s + 1);
            path[x][y] = '.';
            row[x] = col[y] = dg[n + y - x] = udg[x + y] = false;
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        n = input.nextInt();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                path[i][j] = '.';
            }
        }
        dfs(0,0,0);
    }
}

学习基础概念主要了解DFS和BFS的区别,DFS中的回溯剪枝递归以及恢复原样是关键。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值