2014省赛大总结(一) DFS 与 BFS

来源:互联网 发布:淘宝金冠猪哼少被曝光 编辑:程序博客网 时间:2024/06/14 13:18

第一部分:DFS

        DFS(深度优先搜索),深度优先搜索法与回溯法差不多,主要的区别是回溯法在求解过程中不保留完整的树结构,而深度优先搜索则记下完整的搜索树,搜索树起记录解路径和状态判重的作用。为了减少存储空间,在深度优先搜索中,用标志的方法记录访问过的状态,这种处理方法使得深度优先搜索法与回溯法没什么区别了。

        深度优先搜索所遵循的搜索策略是尽可能“深”地搜索图。在深度优先搜索中,对于最新发现的结点,如果它还有以此为起点而未搜过的边,就沿着边继续搜索下去。当结点v的所有边都已被探寻过,搜索将回溯到发现结点v有那条边的始结点。这一过程一直进行到已发现从源结点可达的所有结点为止。如果还存在未被发现的结点,则选择其中一个作为源结点并重复以上过程,整个过程反复进行直到所有结点都被发现为止。

        代表题目:N皇后问题 


#include<stdio.h>   #define N 15     int n; //皇后个数   int sum = 0; //可行解个数   int x[N]; //皇后放置的列数       int place(int k)   {       int i;       for(i=1;i<k;i++)         if(abs(k-i)==abs(x[k]-x[i]) || x[k] == x[i])           return 0;       return 1;   }       int queen(int t)   {       if(t>n && n>0) //当放置的皇后超过n时,可行解个数加1,此时n必须大于0         sum++;       else        for(int i=1;i<=n;i++)         {             x[t] = i; //标明第t个皇后放在第i列             if(place(t)) //如果可以放在某一位置,则继续放下一皇后               queen(t+1);          }       return sum;   }     int main()   {       int t;       scanf("%d",&n);       t = queen(1);       if(n == 0) //如果n=0,则可行解个数为0,这种情况一定不要忽略         t = 0;       printf("%d",t);       return 0;   }  

      

        DFS的限制在于溢出危险,因为DFS的递归实现复杂度在 O(n^2)以上 (实例代码的复杂度为 O(n^3 *1/ 3)),在N比较多的情况下,时间和空间的开销都是巨大的,所以在使用过程中要注意剪枝操作的灵活运用。


第二部分:BFS

        BFS(宽度优先遍历,又称广度优先搜索算法的核心思想是:从初始结点开始,应用算符生成第一层结点,检查目标结点是否在这些后继结点中,若没有,再用产生式规则将所有第一层的结点逐一扩展,得到第二层结点,并逐一检查第二层结点中是否包含目标结点。若没有,再用算符逐一扩展第二层所有结点……,如此依次扩展,直到发现目标结点为止。

       代表题目:HDU 1072 Nightmare

       题目大意:在迷宫中有一个炸弹,过六个单位时间就会爆炸,要你求一个起点到迷宫的终点的最短距离,迷宫中有时间重置器,当你走到这个格子,炸弹的爆炸时间重新置为0,迷宫中标识为墙壁的格子不能走,到达任意一个格子时,炸弹计数器为0时,则失败。


       解题思路:最短距离,就想到用宽度优先遍历,但是要一个辅助的数组来保存每个格子的时间信息。之前受hdu 1242的影响,认为格子保存的是当前走过路程的最小值,w了很多次。。。。以为每个格子前进一步的花费时间单位是一样的,所以宽度遍历的结果自然是最短距离,由于时间单位有限制,只能走六个单元,只有在这六个时间单位里到达了终点,或者走到了时间设置开关把炸弹计时器置为0才能继续走下去,所以要一个辅助数组来保存每个格子剩余的最大时间单位,只有走到当前的格子的剩余时间单位比之前的大时,这个状态才能加入队列中。

       

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <queue>#include <algorithm>using namespace std;struct node{    int x, y;    int step;    int t;};const int maxn = 9;int dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};int maze[maxn][maxn], graph[maxn][maxn];int n, m, ex, ey, ans;bool bfs(int x, int y);int main(){        int test;    scanf("%d", &test);    while(test-- != 0)    {        scanf("%d %d", &n, &m);        int sx, sy;        for(int i = 0; i < n; i++)        {            for(int j = 0; j < m; j++)            {                scanf("%d", &maze[i][j]);                if(maze[i][j] == 2)                    sx = i, sy = j;                if(maze[i][j] == 3)                    ex = i, ey = j;                graph[i][j] = 0;            }        }        if(bfs(sx, sy))            printf("%d\n", ans);        else            printf("-1\n");    }        return 0;}bool bfs(int x, int y){    queue<node> que;    node s;    s.x = x;    s.y = y;    s.step = 0;    s.t = 6;    graph[x][y] = 6;    que.push(s);    while(!que.empty())    {        node st = que.front();        que.pop();        if(st.x == ex && st.y == ey)        {            ans = st.step;            return true;        }        if(st.t == 1)            continue;        for(int i = 0; i < 4; i++)        {            int dx = st.x + dir[i][0];            int dy = st.y + dir[i][1];            if(dx >= 0 && dx < n && dy >= 0 && dy < m && maze[dx][dy] != 0)            {                node tmp;                tmp.x = dx; tmp.y = dy;                tmp.step = st.step + 1;                tmp.t  = st.t - 1;                if(maze[dx][dy] == 4)                    tmp.t = 6;                if(tmp.t > graph[dx][dy])                {                    graph[dx][dy] = tmp.t;                    que.push(tmp);                }            }        }    }    return false;}

        宽度优先搜索是最简单的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijksta单源最短路径算法和Prim最小生成树算法都采用了与宽度优先搜索类似的思想。

        BFS的空间限制性比DFS少了很多,溢出的隐患几乎不存在,但是时间复杂度依然不小。BFS的判断重复如果直接判断十分耗时,一般可以借助哈希表来优化,这里不再赘述


这两种搜索在平时的运用非常广泛,我们应该做到对这两种的运作方式烂熟于胸,这对以图论的学习十分有帮助。

0 0
原创粉丝点击