(Basic algorithm学习笔记)《基础算法四》- 深度优先搜索(Depth First Search,DFS )

来源:互联网 发布:python程序员工资 编辑:程序博客网 时间:2024/06/05 04:51

深度优先搜索

深度优先搜索(Depth First Search,DFS )
先引入一个 example

  1. 现在 我们有 三个盒子 排序 1 , 2 , 3
    我们手里也有三个卡牌 1 , 2 , 3
    首先我们约定一个规则: 每次到达一个盒子的时候 都是先放1再放2最后放3
#include <stdio.h>#include <stdlib.h>int boxes[10];  //  1-9 个盒子 int books[10];  //  记录 卡牌是否扔进盒子里,就是记录是否使用了 卡牌,使用则为1 没用则为0int n;   // 输入的  盒子数 // Depth First Search    //step: 第step盒子 void DFS(int step){        int i;       //step = n+1  说明 递归 之前的 n步都已经完成即所有的 数都已经扔进盒子里了此时  打印 顺序即可        if(step == n+1)       {           for(i=1; i<=n; i++)           {               printf("%d",boxes[i]);           }           printf("\n");           return ;   // 此时  返回到上一次的递归的地方(即最近一次调用DFS函数的位置)        }       //  遍历 1 - n的数字        // 此时选择数字扔到  step号码盒子里        for(i=1; i<=n; i++)       {           // i这个数字没有放入 盒子里            if(books[i] == 0)           {              //往step这个盒子里放入i这个数字               boxes[step] = i;              // 相当于flag  此时 这个i数字已经被记录 放入盒子里了               books[i] = 1;              // step盒子 放入后开始  实施下一个盒子的操作               DFS(step+1);              // 得到 递归回来的时候说明 以下的 递归的可能都 遍历完了之后回来              // 还需要把之前递归 放入的数字 拿出来之后才能继续 放数字               books[i] = 0;            }       }        return ;}int main(int argc, char *argv[]){         scanf("%d",&n);     DFS(1);// 从  第一个盒子开始放数字      system("PAUSE");       return 0;}

有详细注释仔细看完大概有以下几个概念:
(1).这也是一种遍历,但是是一种递归的方式更加 巧妙
(2).因为用的是递归所以每一步的操作相同(也是算法核心基础
(3).有标志位来记录 是否用过数字并且在 递归之后有个 books[i]=0的操作

2 、 现在可以 基础写出深度优先搜索的伪代码

void DSF(int step){   判断边界(一个结束的条件之后return)   尝试每一种可能(一般是for循环)   {      这一步结束后      继续下一步的操作(递归)DSF(step+1);   }   return(返回)}

3、 之后的 一个例子就是按这个 方式来写
回忆一下前一个博客写的枚举算法中的 那个 问题三位数+三位数= 三位数

这回我们采用这种方法来写
分析:
(1):首先来看条件:结束条件 为 满足 三位数+三位数=三位数 这个等式即可 之后输出这个组合
(2): 尝试每一个可能,咱们可以类比一下,将数字分成1-9个数字
而三位数的百位,十位,个位为 相应的箱子,其实还是往箱子里面 扔数字,之后 满足(1)的条件 返回 即可开始尝试下一个组合

见代码(在上面的代码上稍作修改):

#include <stdio.h>#include <stdlib.h>int boxes[10];  //  1-9 个盒子 int books[10];  //  记录 卡牌是否扔进盒子里,就是记录是否使用了 卡牌,使用则为1 没用则为0int total;//  组合的个数 // Depth First Search    //step: 第step盒子 void DFS(int step){        int i;       //step = n+1  说明 递归 之前的 n步都已经完成即所有的 数都已经扔进盒子里了此时  打印 顺序即可        if(step == 10)//n修改        {               //  条件修改            if(boxes[1]*100+boxes[2]*10+boxes[3]+boxes[4]*100+boxes[5]*10+boxes[6] == boxes[7]*100+boxes[8]*10+boxes[9])           {                total ++;                printf("%d%d%d+%d%d%d=%d%d%d\n",boxes[1],boxes[2],boxes[3],boxes[4],boxes[5],boxes[6],boxes[7],boxes[8],+boxes[9]);           }            return ;   // 此时  返回到上一次的递归的地方(即最近一次调用DFS函数的位置)        }       //  遍历 1 - n的数字        // 此时选择数字扔到  step号码盒子里        for(i=1; i<=9; i++)// n修改        {           // i这个数字没有放入 盒子里            if(books[i] == 0)           {              //往step这个盒子里放入i这个数字               boxes[step] = i;              // 相当于flag  此时 这个i数字已经被记录 放入盒子里了               books[i] = 1;              // step盒子 放入后开始  实施下一个盒子的操作               DFS(step+1);              // 得到 递归回来的时候说明 以下的 递归的可能都 遍历完了之后回来              // 还需要把之前递归 放入的数字 拿出来之后才能继续 放数字               books[i] = 0;            }       }        return ;}int main(int argc, char *argv[]){         DFS(1);// 从  第一个盒子开始放数字      printf("total=%d",total/2);      system("PAUSE");       return 0;}

3、 再来个例子,再来试着和我一起分析一下
现在有一个迷宫 0代表 可以走的地方 1代表 障碍物
一个 人加入在 (3,4)这个位置,我们从(1,1)走 怎么去 最快的找到他 ,顾名思义,可能是 最短距离去搜索对吧? 此处我们来用 深度优先搜索

(1) 首先制定一个规则,每次 我们都 先尝试向右, 向下,向左,向上的顺序 来 走
(2) 最后的条件为 达到 那个 人的 位置则为 条件满足(其实就是x和y坐标满足,之后 来找出最小的 path则 需要 进行比较赋值处理看一眼代码你就懂了 )
(3) 遍历还是 遍历 右下左上,去遍历这里我们可以 来定义一个数组来表示 这四个操作
(4) 遍历的过程中 有条件限制:
a. 越界 越界的话直接 尝试 下一个 操作即 通过continue来 实现
b. 是否是 障碍物 需要判断 障碍物不能行走
c. 这里很容易 忘掉的 一点,那就是 你以前走过的路 应该不需要 再走回去吧???所以 这里也需要if条件判断
那么好 现在已经全部分析完成开始准备代码
代码如下:

#include <stdio.h>#include <stdlib.h>int aimX,aimY;// 目标x,y int minStep = 99999999 ;  // 最短距离 int n,m;      // n为行,m为列  int boxes[51][51];    // 迷宫   int books[51][51]; // 走过的 标志 void DFS(int x, int y, int step){       //向右,向下,向左,向上       int next[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};      int tx,ty,i;      // 满足的条件  抵达目标处        if((x==aimX)&&(y==aimY))      {          // 要最小的 路程步数          if(minStep>step)         {             minStep = step;            }           return ;                             }      // 遍历 四个 走向       for(i=0; i<=3; i++)      {           // 更新 x,y坐标           tx = x + next[i][0];          ty = y + next[i][1];          //判断是否越界  越界 则 调到下一个走向           if(tx<1 || tx>n || ty<1 || ty>m)           {               continue;           }           //1. 判断是否 为平地即无障碍物           //2. 判断这一点是否走过            if((boxes[tx][ty] == 0)&&(books[tx][ty]==0))          {               books[tx][ty] = 1;// 标志这个点走过了                DFS(tx,ty,step+1);// 下一个点的操作                books[tx][ty] = 0;// 遍历结束将走过的点的标志去掉           }      }       return;}int main(int argc, char *argv[]){         int i,j;     int startx,starty;//开始的 x,y坐标      scanf("%d %d",&n,&m);     for(i=1;i<=n;i++)     {        for(j=1;j<=m;j++)        {            scanf("%d",&boxes[i][j]);        }     }     scanf("%d %d %d %d",&startx,&starty,&aimX,&aimY);     books[startx][starty] = 1;//先记录 起始点 走过了 要不会多一次遍历。      DFS(startx,starty,0);     printf("%d",minStep);     system("PAUSE");       return 0;}

输入
5 4
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
1 1 4 3

显示
7请按任意键继续…

阅读全文
0 0
原创粉丝点击