• [算法&数据结构]深度优先搜索(Depth First Search)


    深度优先 搜索(DFS, Depth First Search)
    从一个顶点v出发,首先将v标记为已遍历的顶点,然后选择一个邻接于v的尚未遍历的顶点u,如果u不存在,本次搜素终止。如果u存在,那么从u又开始一次DFS。如此循环直到不存在这样的顶点。

    算法核心代码如下:

        void dfs(int step){
    
            // 判断边界是否成立
    
            // 尝试每一种可能
            for(int i=0;i<n;i++){
                // 
                // 继续执行下一步
                dfs(step + 1)
                // 取消已被使用标记
            }
    
        }
    
    

    全排列

    下面我们利用一个简单基本案例来学习全排列

    A 手中有3张牌,分别是1,2,3 那么请问这三张牌能组成多少位不重复三位数字?

    DFS算法分析

    • 首先我们假设有三个桶,桶里面可以存放牌,那么我们来到第一个桶,我们手里有3张牌,按照顺序,我我们可以放入1,然后完成当前操作,标记第一张牌已经被使用,来到第二个桶里面,开始尝试,尝试放入第一张牌,此时1已经被使用了,所以我们尝试2,那么第二个桶也已经被放入数据了,2被标记为使用,接着来到第3个桶,此时,我们尝试放入1,1被使用,无法放入,尝试放入2,2也被使用,尝试放入3,OK,3 放入成功,此时三个桶放入完成,完成一次全排列,即1,2,3

    • 好,回到第3个桶,的时候我们没有其他牌可以放了,1,2已经被使用,3正在桶里呢,我们继续回到2号桶,同时标记3号牌未被使用,回到2号桶,此时2号桶已经尝试了1,2 那么我们继续尝试3号牌,3号牌刚刚被收回,可以放入,此时2号桶放入3号牌,继续第3个桶,同样的依次尝试所有的可能,1号牌不行,2号可以,此时完成了全排列1,3,2

    • 继续,回到3号桶,没有可用的了,回到2号桶,3号牌也被用了,也没有了,继续回到1号桶,此时1号桶放入的是1,那么我们收回,继续放入2号牌,来到2号桶,此时手中有1,3号,我们放入1,来到3号桶,1,2已被使用,我们只能放入3,又完成一次全排列2,1,3

    • 依次类推....

    那么我们看下代码,这里提供了C语言版本的和Java语言版本的,原理是一样的

    C语言版本

    代码

    #include <stdio.h>
    
    // 定义扑克牌长度 3
    #define PLAY_CARD_SIZE 3
    // 定义数组
    int numbers[] = {1,2,3};
    
    // 标记数字是否被使用
    int status[] = {0, 0, 0};
    
    // 定义位置
    int location[] = {0,0,0};
    
    /**
     * 声明dfs方法
     * @param step  当然位置
     */
    void dfs(int step);
    
    int main(){
        dfs(0);
        return 0;
    }
    
    
    void dfs(int step){
        // 判断搜索临界条件
        if (step == 3){
            for (int i = 0; i < 3; ++i) {
                printf("%d,",location[i]);
            }
            printf("
    ");
            // 完成此次全排列
            return;
        }
    
        for (int j = 0; j < 3; ++j) {
            if(status[j] == 0){
                location[step] = numbers[j];
                status[j] = 1;
                dfs(step + 1);
                status[j] = 0;
            }
        }
    }
    
    

    输出结果

    1,2,3,
    1,3,2,
    2,1,3,
    2,3,1,
    3,1,2,
    3,2,1,
    
    

    Java语言版本

    代码

    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 深度优先搜寻算法
     */
    public class DFS2 {
    
        // 定义扑克牌的数量
        static int PLAY_CARD_SIZE = 3;
        // 存放扑克牌的集合
        static List<PlayCard> playCards = new ArrayList<>();
        // 存放扑克牌的位置
        static String[] numbers = new String[PLAY_CARD_SIZE];
    
        // 初始化扑克牌 1,2,3
        static {
            for (int i = 0; i < PLAY_CARD_SIZE; i++) {
                playCards.add(new PlayCard(String.valueOf(i + 1), false));
            }
        }
    
        // 程序入口
        public static void main(String[] args) {
            dfs(0);
        }
    
        private static void dfs(int startIndex) {
    
            if (startIndex == playCards.size()){
                for (int i = 0;i<numbers.length;i++){
                    System.out.print(numbers[i]+",");
                }
                System.out.println("");
                System.out.println("-------------");
                return;
            }
    
            for (int i = 0; i < playCards.size(); i++) {
                if(!playCards.get(i).used){
                    playCards.get(i).used = true;
                    numbers[startIndex] = playCards.get(i).code;
                    dfs(startIndex + 1);
                    playCards.get(i).used = false;
                }
            }
    
    
        }
    
        // 封装的实体类,为了方便定义为public
        static class PlayCard {
            public PlayCard(String code, boolean used) {
                this.code = code;
                this.used = used;
            }
    
            // 扑克牌编号 ,即1,2,3
            public String code;
    
            // 扑克牌是否已被使用
            public boolean used;
        }
    
    }
    
    

    输出结果

    1,2,3,
    1,3,2,
    2,1,3,
    2,3,1,
    3,1,2,
    3,2,1,
    

    等式求解

    想起来以前有个题目,计算恒等式,题目是a[0] * 100 + a[1] * 10 + a[2] +a[3] * 100 + a[4] * 10 + a[5] == a[6] * 100 + a[7] * 10 +a[8] 问a的组合有多少种?

    Ps:a是0-9组成的,不可重复

    下面我们有DFS来实现这个题目,记得在以前,肯定是写九个for循环嵌套,现在我们尝试利用上面的全排列来判断,此时的输出(边界条件)修改为上面的等式,代码不做过多的阐述了。没有了9层循环的样子。。。。

    代码

    public class DFS3 {
    
        static int PLAY_CARD_SIZE = 9;
        static List<Number> playCards = new ArrayList<>();
        static int[] a = new int[PLAY_CARD_SIZE];
    
        static {
            for (int i = 1; i <= PLAY_CARD_SIZE; i++) {
                playCards.add(new Number(i, false));
            }
        }
    
    
        public static void main(String[] args) {
            dfs(0);
        }
    
        private static void dfs(int startIndex) {
    
            if (startIndex == playCards.size()) {
                if (checkNumber()) {
                    for (int i=0;i<PLAY_CARD_SIZE;i++){
                        System.out.print(a[i]+",");
                    }
                    System.out.println();
                }
                return;
            }
    
            for (int i = 0; i < playCards.size(); i++) {
                if (!playCards.get(i).used) {
                    playCards.get(i).used = true;
                    a[startIndex] = playCards.get(i).code;
                    dfs(startIndex + 1);
                    playCards.get(i).used = false;
                }
            }
        }
    
        /**
         * 判断搜索边界
         *
         * @return
         */
        private static boolean checkNumber() {
            if(a[0] * 100 + a[1] * 10 + a[2] +a[3] * 100 + a[4] * 10 + a[5] ==  a[6] * 100 + a[7] * 10 +a[8])
                return true;
            return false;
        }
    
        static class Number {
            public Number(int code, boolean used) {
                this.code = code;
                this.used = used;
            }
    
            public int code;
            public boolean used;
        }
    
    }
    
    

    输出结构

    输出结构也是蛮多的,这里摘录几个,可以自己测试下

    1,2,4,6,5,9,7,8,3,
    ...
    2,1,4,5,6,9,7,8,3,
    ...
    3,1,4,6,5,8,9,7,2,
    ...
    4,1,5,2,7,8,6,9,3,
    ...
    5,9,6,2,4,1,8,3,7,
    ...
    6,9,5,1,4,2,8,3,7,
    ...
    7,8,4,1,5,2,9,3,6,
    

    总结

    DFS 是一个非常有意思的算法,在图解中和BFS也属于非常重要的算法了,多多理解,多多学习

  • 相关阅读:
    codeforces 1060 B
    codeforces 1060 A
    牛客 国庆七天乐 day1 L
    BZOJ 1087: [SCOI2005]互不侵犯King
    codeforces 792CDivide by Three(两种方法:模拟、动态规划
    codeforces 797C Minimal string
    codeforces 110E Lucky Tree
    codeforces 798D
    2017福建省赛 FZU2272~2283
    Android -- Looper、Handler、MessageQueue等类之间关系的序列图
  • 原文地址:https://www.cnblogs.com/zhoutao825638/p/10382285.html
Copyright © 2020-2023  润新知