`
SIHAIloveYAN
  • 浏览: 124592 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类

BFS算法详解

 
阅读更多

一、概述

  作为搜索算法的一种,DFS对于寻找一个解的NP(包括NPC)问题作用很大。但是,搜索算法毕竟是时间复杂度是O(n!)的阶乘级算法,它的效率非常低,在数据规模变大时,这种算法就显得力不从心了。当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。

  这些是百度上面的一些话,根据自己理解,就是说这个算法运用的时候就是找一个头结点,然后沿着这个头结点一直找下去,直到走到最后一个满足条件的分节点,然后再寻找另一条路径,当沿着一条路走不满足条件时会自动的跳入上一层节点进行判断。
  dfs算法通常与回溯算法一起使用,下面的例子中将会提到这些问题。每次做这种类型的题可以先画出dfs遍历的路径图,这样有利于写程序时的合理思维

二、实例讲解

2.1、例题1

Description
Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长底滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子
1 2 3 4 5

16 17 18 19 6

15 24 25 20 7

14 23 22 21 8

13 12 11 10 9

一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。
Input
输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。
Output
输出最长区域的长度。
Sample Input
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
Sample Output
25
 #include<iostream>  
    #include<cstdio>  
    using namespace std;  

    int R, C;  
    int map[105][105];  
    int mark[105][105] = { 0 };  


    int dfs(int i, int j)  
    {  
    int k;  
    if (mark[i][j]) return mark[i][j];  
    if (i != 0 && map[i - 1][j] < map[i][j])  
    {  
    k = dfs(i - 1, j) + 1;  
    if (k> mark[i][j]) mark[i][j] = k;  
    }  
    if (i != R - 1 && map[i + 1][j] < map[i][j])  
    {  
    k = dfs(i + 1, j) + 1;  
    if (k>mark[i][j]) mark[i][j] = k;  
    }  
    if (j != 0 && map[i][j - 1]<map[i][j])  
    {  
    k = dfs(i, j - 1) + 1;  
    if (k>mark[i][j]) mark[i][j] = k;  
    }  
    if (j != C - 1 && map[i][j + 1]<map[i][j])  
    {  
    k = dfs(i, j + 1) + 1;  
    if (k>mark[i][j]) mark[i][j] = k;  
    }  
    return mark[i][j];  

    }  

    int main()  
    {  
    int i, j, k, sum = 0;  
    scanf("%d%d", &R, &C);  
    for (i = 0; i < R; i++)  
    {  
    for (j = 0; j < C; j++)  
    {  
    scanf("%d", &map[i][j]);  
    }  
    }  
    for (i = 0; i < R; i++)  
    {  
    for (j = 0; j < C; j++)  
    {  
    k = dfs(i, j);  
    if (k>sum) sum = k;  
    }  
    }  
    cout << sum + 1 << endl;  
    return 0;  
    }  

解析:这个题就是把每个数从四个方向都遍历一次,如果满足递减的话就接着dfs,不满足时候把这个数存起来
这个题有几个注意的问题,就是第一个要考虑好边缘临界点,就是四周的点不可以进行某些方向的移动,其次还有一点特别要注意,dfs中的if (mark[i][j]) return mark[i][j];这句话就是为了重复计算,假如从24开始的话已经算出来23,然后如果从25开始,遇到24的话直接可以找到23,而不用在遍历一次,节省了时间。

2.2、实例2

八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当 n = 1 或 n ≥ 4 时问题有解。


Input
无输入。

Output
按给定顺序和格式输出所有八皇后问题的解(见Sample Output)。

Sample Input

Sample Output

No. 1
1 0 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 0 0 1 0 0 0 
0 0 0 0 0 0 0 1 
0 1 0 0 0 0 0 0 
0 0 0 1 0 0 0 0 
0 0 0 0 0 1 0 0 
0 0 1 0 0 0 0 0 
No. 2
1 0 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 0 1 0 0 0 0 
0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 1 
0 1 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 
0 0 1 0 0 0 0 0 
No. 3
1 0 0 0 0 0 0 0 
0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 1 
0 0 1 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 0 1 0 0 0 0 
0 1 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 
No. 4
1 0 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 
0 0 0 0 0 0 0 1 
0 0 0 0 0 1 0 0 
0 0 1 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 1 0 0 0 0 0 0 
0 0 0 1 0 0 0 0 
No. 5
0 0 0 0 0 1 0 0 
1 0 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 
0 1 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 
0 0 1 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 0 1 0 0 0 0 
No. 6
0 0 0 1 0 0 0 0 
1 0 0 0 0 0 0 0 
0 0 0 0 1 0 0 0 
0 0 0 0 0 0 0 1 
0 1 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 1 0 0 0 0 0 
0 0 0 0 0 1 0 0 
No. 7
0 0 0 0 1 0 0 0 
1 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 1 
0 0 0 1 0 0 0 0 
0 1 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 1 0 0 0 0 0 
0 0 0 0 0 1 0 0 
No. 8
0 0 1 0 0 0 0 0 
1 0 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 0 0 1 0 0 0 
0 0 0 0 0 0 0 1 
0 1 0 0 0 0 0 0 
0 0 0 1 0 0 0 0 
0 0 0 0 0 1 0 0 
No. 9
0 0 0 0 1 0 0 0 
1 0 0 0 0 0 0 0 
0 0 0 1 0 0 0 0 
0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 1 
0 1 0 0 0 0 0 0 
0 0 0 0 0 0 1 0 
0 0 1 0 0 0 0 0 
...以下省略

解析:这个就是定义hang 【num】和列i,然后每一行从第一个位置开始放皇后,如果可以的话就标记为1,然后接着往下找第二行,也是从第二行第一个位置开始找,满足接着第三行。当如果发现第三行不能再放置皇后了,这个时候第三行那个位置已经标记为1 ,所以这个时候就回溯到第二行也就是上一层从新判断同时把标记为1 的变量还原为0,直到满足条件输出。题中有一个陷阱,深搜的时候是按列输出的,不是行输出。

  #include<iostream>  
    #include<cstdio>  
    #include<cstdlib>  
    using namespace std;  
    int hang[11], n=8;  
    int a[10][10] = { 0 };  
    int t = 1;  
    void print()  
    {  
        printf("No. %d\n", t++);  
        for (int i = 1; i <= 8; i++)  
        {  
            for (int j = 1; j <= 8; j++)  
            {  
                printf("%d ", a[j][i]);  
            }  
            printf("\n");  
        }  
    }  
    bool judge(int num)  
    {  
        for (int i = 1; i < num; i++)  
            if (hang[num] == hang[i] || abs(hang[i] - hang[num]) == num - i)  
                //判断列和对角线  
                return 0;  
        return 1;  
    }  

    void dfs(int num)  
    {  
        if (num >= 9){  
            print();  
        }  
        for (int i = 1; i <= 8; i++)  
        {  
            hang[num] = i;  
            if (a[num][i]!=1&&judge(num))  
            {  
                a[num][i] = 1;  
                dfs(num + 1);  
                a[num][i] = 0;  
            }  

        }  

    }  

    int main()  
    {  
        //freopen("1.txt", "w", stdout);  
            dfs(1);  
        return 0;  
    }  

2.3、实例3

最后在来一个dfs解决迷宫问题,就是1代表障碍,0代表通过,然后问从头到尾一共有几条路径可以走到终点,这个问题同样是dfs加回溯,就是遍历每一个走过点的上下左右四个方向,直到最后走到终点再重新回溯就是return 1,把走过的还原为0,(因为走过的路都标记为1),最后return sum把顺带可以return的结果输出。

  /* 
      输入两个数n,m,代表迷宫的行和列 
      接下来输入n行m列由0,1组成的迷宫,其中1代表障碍 
      求从左上角到右下角的路线个数 
    */  
    #include<stdio.h>  
    #define N 1000//最大行列数  
    int mg[N][N];//存放迷宫图  
    int re[N][N];//记录之前是否走过  
    int n, m;//行,列  
    int dfs(int x, int y){//现在在(x,y)点  
        if(x < 0 || x > n - 1 || y < 0 || y > m - 1 || re[x][y] == 1 || mg[x][y] == 1) return 0;//走出界外或之前走过或遇到障碍  
        if(x == n - 1 && y == m - 1) return 1;//走到终点  
        re[x][y] = 1;//该点标记为走过  
        int sum = 0;  
        sum += dfs(x - 1, y);//向左走  
        sum += dfs(x + 1, y);//向右走  
        sum += dfs(x, y - 1);//向上走  
        sum += dfs(x, y + 1);//向下走  
        re[x][y] = 0;//该点还原为没有走过  
        return sum;  
    }  
    int main(){  
        int i, j;  
        while(~scanf("%d%d", &n, &m)){//输入行列  
            for(i = 0; i < n; i ++)  
            {  
                for(j = 0; j < m; j ++) scanf("%d", &mg[i][j]);//读入迷宫图  
            }  
            printf("%d\n", dfs(0, 0));//输出结果  
        }  
        return 0;  
    }  
<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
分享到:
评论

相关推荐

    dfs和bfs算法详解.md

    DFS(深度优先搜索)和BFS(广度优先搜索)是两种在计算机科学中非常重要的图遍历算法,它们在处理树或图结构时具有不同的特点和应用场景。 深度优先搜索(DFS)是一种回溯算法,它沿着一条路径深入直至无法继续,...

    BFS.zip_Bfs算法_图BFS算法

    **BFS算法详解** 在计算机科学中,图遍历是一种重要的算法,用于探索图的所有节点。其中,广度优先搜索(Breadth-First Search,简称BFS)是一种按照节点的层次顺序遍历图的方法。BFS算法尤其适用于寻找最短路径、...

    bfs.rar_Boost_bfs

    **Boost库与BFS算法详解** Boost库是一个开源的C++库集合,它为C++标准库提供了大量的扩展,涵盖了各种编程任务,包括图形算法、并发处理、数学运算以及许多实用工具。在Boost库中,虽然没有直接提供广度优先搜索...

    bfs-dfs.rar_BFS algoritm_BFS+c++

    **BFS算法详解** 广度优先搜索(BFS)是一种用于遍历或搜索树或图的算法。在图中,它从根节点开始,逐层地访问所有相邻节点,然后再去访问下一层的节点。BFS通常用于找出两个节点之间的最短路径,尤其是在所有边的...

    BFS.rar_Bfs算法_bfs_广度优先_广度搜索算法_搜索算法

    **广度优先搜索(BFS)算法详解** 广度优先搜索(BFS)是一种用于遍历或搜索树或图的算法。它从根节点开始,然后遍历所有相邻的节点,然后再对每个相邻节点进行相同的操作,直到遍历完所有节点。在图中,BFS算法...

    BFS算法解释、技术难点和要点,实际应用分析

    **广度优先搜索(BFS)算法详解** 广度优先搜索(Breadth-First Search,简称BFS)是一种在图或树结构中进行搜索的算法。它从根节点开始,按照“先遍历所有相邻节点,再遍历下一层次相邻节点”的顺序,逐层进行搜索...

    广度优先搜索算法BFS

    **广度优先搜索(BFS)算法详解** 广度优先搜索(BFS)是一种用于遍历或搜索树或图的算法。它从根节点开始,然后遍历所有相邻的节点,接着对每个相邻节点,再遍历它们的相邻节点,以此类推,直到遍历完所有节点。...

    迷宫求解算法详解:手把手教你实现DFS和BFS

    文章首先解释如何使用二维数组表示迷宫,接着分别介绍了DFS和BFS算法的工作原理和Python实现代码。最后,提供了一个带有用户界面的完整项目示例,帮助读者直观理解和测试算法效果。 适合人群:计算机科学专业的学生...

    二叉树的层次遍历:广度优先搜索(BFS)算法详解与Python实现

    在计算机科学中,二叉树的遍历是算法和数据结构领域的基础内容之一,其方法主要分为深度优先搜索(DFS)和广度优先搜索(BFS)。广度优先搜索(BFS)是一种按层次遍历二叉树的方法,也称为层次遍历。这种方法按照树...

    栈和队列 算法详解

    而队列则适用于处理有序或按照时间顺序的问题,如广度优先搜索(BFS)和事件驱动的模拟。 在实际编程中,我们可以使用数组或者链表来实现栈和队列。数组实现简单,但是大小固定,可能导致空间浪费;链表则更加灵活...

    BFS.zip_bfs_in

    在这个特定的压缩包文件"BFS.zip_bfs_in"中,包含了一个C语言实现的BFS算法,以及与罗马尼亚国家的图遍历示例相关的资源。 1. **Breadth First Search 算法原理** BFS的核心思想是使用队列数据结构来存储待访问的...

    bfs.rar_BFS c++_bfs

    **广度优先搜索(BFS)算法详解及C++实现** 在计算机科学中,图遍历是探索图的所有节点的一种基本方法。其中,广度优先搜索(BFS)是一种常用的图遍历策略,尤其适用于寻找最短路径或者解决迷宫问题。本篇将详细...

    ACM算法设计-BFS-DFS详解_算法_dfs_ACM_zoouts_bfs_

    在"ACM算法设计-BFS(广度搜索)-DFS入门(深度搜索)详解.ppt"这个文件中,你可能会学到如何使用这两种算法的详细步骤,包括它们的伪代码、实际示例和应用场景。文件可能还会包含相关的编程语言实现,如C++或Python,...

    bfs.zip_bfs

    **广度优先搜索(BFS)算法详解** 在计算机科学中,广度优先搜索(Breadth-First Search,简称BFS)是一种用于遍历或搜索树或图的算法。这个算法从根节点开始,然后访问所有相邻节点,再对每个相邻节点进行同样的...

    算法之BFS与DFS

    提供的压缩包文件包含了多个关于BFS和DFS的讲解资料,如"关于bfs与dfs.pdf"、"07_ACM_DFS+BFS.ppt"、"搜索(BFS_和_DFS).ppt"和"ACM算法设计-BFS(广度搜索)-DFS入门(深度搜索)详解.ppt"。这些资源详细介绍了这两种...

    经典算法详解

    本经典算法研究系列,涵盖 A*.Dijkstra.DP.BFS/DFS.红黑树.KMP.遗传.启发式搜索.图像特征提取SIFT.傅立叶变换.Hash.快速排序.SPFA.快递选择 SELECT 等15 个经典基础算法,共计 31 篇文章,包括算法理论的研究与阐述...

    BFS.rar_bfs

    **广度优先搜索(BFS)算法详解** 在计算机科学中,广度优先搜索(BFS)是一种用于遍历或搜索树或图的算法。它按照节点的层次,从根节点开始,逐层进行访问,直到找到目标节点为止。BFS在解决许多问题时都非常有用...

    ACM常用搜索算法详解

    A*搜索算法是一种启发式搜索算法,结合了DFS和BFS的优点,通过一个评估函数(f(n) = g(n) + h(n))来指导搜索,其中g(n)是从起点到节点n的实际成本,h(n)是从节点n到目标的估计成本。A*算法能够在保证最优解的情况下...

    网络流算法详解

    ### 网络流算法详解 #### 一、引言 网络流算法是计算机科学与数学领域中的一个重要分支,广泛应用于资源分配、物流规划、任务调度等实际问题中。其中,最大流问题是最基本的问题之一,它研究的是如何在网络中找到...

    leetCode一线大厂算法详解+代码

    《leetCode一线大厂算法详解+代码》是一个针对程序员面试准备的重要资源,它涵盖了大量算法题目及对应的解题代码,旨在帮助求职者提升算法能力,顺利通过一线大厂的面试。这里的“一线大厂”通常指的是如阿里巴巴、...

Global site tag (gtag.js) - Google Analytics