zoukankan      html  css  js  c++  java
  • 深搜

    深搜

    搜索与回溯是计算机解题中常用的算法,很多问题无法根据某种确定的计算法则来求解,可以利用搜索与回溯的技术求解。回溯是搜索算法中的一种控制策略。它的基本思想是:为了求得问题的解,先选择某一种可能情况向前探索,在探索过程中,一旦发现原来的选择是错误的,就退回一步重新选择,继续向前探索,如此反复进行,直至得到解或证明无解。

    如迷宫问题:进入迷宫后,先随意选择一个前进方向,一步步向前试探前进,如果碰到死胡同,说明前进方向已无路可走,这时,首先看其它方向是否还有路可走,如果有路可走,则沿该方向再向前试探;如果已无路可走,则返回一步,再看其它方向是否还有路可走;如果有路可走,则沿该方向再向前试探。按此原则不断搜索回溯再搜索,直到找到新的出路或从原路返回入口处无解为止。

    递归回溯法算法框架[]

    int Search(int k)

     {

     for (i=1;i<=算符种数;i++)

      if (满足条件)

         {

        保存结果

        if (到目的地) 输出解;

         else Search(k+1);

        恢复:保存结果之前的状态{回溯一步}

         }

     }

    递归回溯法算法框架[]

    int Search(int k)

     {

       if  (到目的地) 输出解;

       else

        for (i=1;i<=算符种数;i++)

         if  (满足条件)

           {

            保存结果;

                 Search(k+1);

            恢复:保存结果之前的状态{回溯一步}

           }

    }

    哈哈哈,熟悉的八皇后也匆匆忙忙的过来了

    【题目】八皇后问题:要在国际象棋棋盘中放八个皇后,使任意两个皇后都不能互相吃。(提示:皇后能吃同一行、同一列、同一对角线的任意棋子。)

    放置第i个()皇后的算法为:

    int search(i)

     {

         int j;

       for (i个皇后的位置j=1;j<=8;j++ )   //在本行的8列中去试

       if (本行本列允许放置皇后)

        {

         放置第i个皇后;对放置皇后的位置进行标记;

         if (i==8) 输出    //已经放完个皇后

            else search(i+1)//放置第i+1个皇后

         对放置皇后的位置释放标记,尝试下一个位置是否可行;

        }

     }

    【算法分析】

    显然问题的关键在于如何判定某个皇后所在的行、列、斜线上是否有别的皇后;可以从矩阵的特点上找到规律,如果在同一行,则行号相同;如果在同一列上,则列号相同;如果同在/ 斜线上的行列值之和相同;如果同在\ 斜线上的行列值之差相同;从下图可验证:

    考虑每行有且仅有一个皇后,设一维数组A[1..8]表示皇后的放置:第i行皇后放在第j列,用A[i]j来表示,即下标是行数,内容是列数。例如:A[3]=5就表示第3个皇后在第3行第5列上。

    判断皇后是否安全,即检查同一列、同一对角线是否已有皇后,建立标志数组b[1..8]控制同一列只能有一个皇后,若两皇后在同一对角线上,则其行列坐标之和或行列坐标之差相等,故亦可建立标志数组c[1..16]、d[-7..7]控制同一对角线上只能有一个皇后。

    如果斜线不分方向,则同一斜线上两皇后的行号之差的绝对值与列号之差的绝对值相同。在这种方式下,要表示两个皇后IJ不在同一列或斜线上的条件可以描述为:A[I]<>A[J] AND ABS(I-J)<>ABS(A[I]-A[J]){IJ分别表示两个皇后的行号}

    【参考程序】

    int search(int i)//从第1个皇后开始放置

    {

      int j;

      for(j=1;j<=8;j++)   //每个皇后都有8位置()可以试放                                          

    if ((!b[j])&&(!c[i+j])&&(!d[i-j+7]))                   

    //寻找放置皇后的位置,由于C++不能操作负数组,因此考虑加7    {     置皇后,建立相应标志值                                                        a[i]=j;    //摆放皇后                                                   

           b[j]=1;   //宣布占领第j列                                                      

           c[i+j]=1,d[i-j+7]=1;    //占领两个对角线                                           

    if(i==8)  print();      //8个皇后都放置好,输出

    else search(i+1);       //继续递归放置下一个皇后

           b[j]=0,c[i+j]=0;

    d[i-j+7]=0; //递归返回即为回溯一步,当前皇后退出                                 

        }

    }

    【总结】:

    1. 最普遍的剪枝就是可行性剪枝与最优化剪枝,缩小宽度范围(最优化剪枝),贪心化删减dfs的深度
    2. 对于Dfs,确定Dfs的深度是非常重要的,其次注意每次宽度深搜的最大宽度
    3. 深度优先搜索要学会迭代加深,估价函数要求简洁诶
    4. 剪枝的思想一定要贯彻整一场考试,学会舍得,用正确性换空间与时间,可以做,请谨慎点

     感谢各位与信奥一本通的鼎力相助!

  • 相关阅读:
    C#笔记(Hex转JPG)
    rpm 和 yum 软件管理
    名称空间和作用域
    网络技术管理和进程管理
    RAID磁盘阵列
    CentOS7系统启动流程:
    磁盘lvm管理
    面向对象 异常处理
    自定义函数和调用函数 return返回值
    Python常用模块
  • 原文地址:https://www.cnblogs.com/SeanOcean/p/10975590.html
Copyright © 2011-2022 走看看