ACM北大暑期课培训第三天

  今天讲的内容是深搜和广搜

  深搜(DFS)

  从起点出发,走过的点要做标记,发现有没走过的点,就随意挑一个往前走,走不 了就回退,此种路径搜索策略就称为“深度优先搜索”,简称“深搜”。

  

bool Dfs(V) {
if( V 为终点)
return true;
if( V 为旧点
)
return false;
将
V标记为旧点
;
对和
V相邻的每个节点U {
if( Dfs(U) == true)
return true;
}
return false;
}
int main()
{
将所有点都标记为新点;
起点 = 1
终点 = 8
cout << Dfs(起点);
}
判断从 V出发是否能走到终点:

 

  用的时候注意剪枝:最优性剪枝 和 可行性剪枝

  用深搜找最优路径时用最优性剪枝:搜索过程中总长度大于或等于之前所求得的最优解则剪掉。

  另一种通用的最优性剪枝思想 ---保存中间计算结果用于最优性剪枝(用空间换时间)

  可行性剪枝是先判断出这个条件下是否可行,不可行则直接返回。

  两种剪枝可以一起使用。

 

  运用剪枝时复杂度不好估计

 

  搜索顺序 : 一个事若由多个无关步骤组成,应先尝试选择少的 ,选择少的正确率高。

 

        ps:用邻接表存图  (可用vector)此时遍历的时间复杂度为 O(n+e)n为节点数目,e为边数目

    若用邻接矩阵遍历的时间复杂度为O(n2

 

  ps:节省时间的方法:看循环是否能提前break;

 

例题:1.OpenJ_Bailian 2815 城堡问题

     2.OpenJ_Bailian 4103 踩方格

     3.POJ 1724  ROADS

     4.POJ 1190 生日蛋糕

 

  广搜(BFS)

  广搜就是一层一层搜。所需要的存储空间较大。一般用队列来存节点。

  要注意初始状态和目标状态。注意判重

 

  一般状态关系到几个参数判重数组就定义几维。(牵扯到结构体的定义)

  若在你选定的同一状态下会出现不同结果,则考虑的情况少了,需要增加判断参数/维数

  

  若要求输出过程则要记录父节点。

 

  多组时,为防止时间超限可以采用:

    1.双向广搜(DBFS) :从两个方向以广度优先的顺序同时扩展

    2.预处理 (把所有情况都列出来)

    3.A*算法 

 

例题:1.POJ 3278 Catch That Cow

   2.POJ 3984 迷宫问题

   3.OpenJ_Bailian 4116 拯救行动

   4.OpenJ_Bailian 4115 鸣人和佐助

   5.OpenJ_Bailian 4130 Saving Tang Monk

   6.POJ 1077 Eight

   7.HDU 1043 Eight (多组)

 

 

  深搜和广搜的比较:

   1.广搜一般用于状态表示比较简单、求最优策略的问题

     优点:是一种完备策略,即只要问题有解,它就一定可以找到解 。并且,广度优先搜索找到的解,还一定是路径最短的解。 

      缺点:盲目性较大,尤其是当目标节点距初始节点较远时,将产生许多无用的节点,因此其搜索效率较低。需要保存所有扩展出的状态,占用的空间大    2.深搜几乎可以用于任何问题 

     只需要保存从起始状态到当前状态路径上的节点

   3.根据题目要求凭借自己的经验和对两个搜索的熟练程度做出选择

 

  双向广度优先搜索(DBFS)

  DBFS算法是对BFS算法的一种扩展。

  BFS算法从起始节点以广度优先的顺序不断扩展,直到遇到目的节点

  DBFS算法从两个方向以广度优先的顺序同时扩展, 一个是从起始节点开始扩展,另一个是从目的节点扩展,直到一个扩展队列中出现另外一个队列中已经扩展的节点,也就相当于两个扩展方向出现了交点,那 么可以认为我们找到了一条路径。

  比较:

    1.DBFS算法相对于BFS算法来说,由于采用了双向扩展的方式,搜索树的宽度得到了明显的减少,时间复杂度和空间复杂度上都有提高!

    2.假设1个结点能扩展出n个结点,单向搜索要m层能找到答案,那 么扩展出来的节点数目就是: (1-n m)/(1-n)

    3.双向广搜,同样是一共扩展m层,假定两边各扩展出m/2层,则总 结点数目 2 * (1-n m/2)/(1-n)

    4.每次扩展结点总是选择结点比较少的那边进行扩展,并不是机械的两边交替。

 

DBFS的框架:需要两个标志序列,分别记录节点是否出现在两个队列中

void dbfs()
{
1. 将起始节点放入队列q0,将目标节点放入队列q1;
2. 当两个队列都未空时,作如下循环:
  1) 如果队列q0里的节点比q1中的少,则扩展队列q0;
  2) 否则扩展队列q1
3. 如果队列q0未空,不断扩展q0直到为空;
4. 如果队列q1未空,不断扩展q1直到为空;
}
int expand(i) //其中i为队列的编号,0或1
{
  取队列qi的头结点H;
  对H的每一个相邻节点adj:
  1 如果adj已经在队列qi之中出现过,则抛弃adj;
  2 如果adj在队列qi中未出现过,则:
    1) 将adj放入队列qi;
    2) 如果adj 曾在队列q1-i中出现过, 则:输出找到的路径
} 

 

转载于:https://www.cnblogs.com/l999q/p/9368258.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行程实践、外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值