深搜

深搜

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

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

 

递归回溯法算法框架[]

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. 剪枝的思想一定要贯彻整一场考试,学会舍得,用正确性换空间与时间,可以做,请谨慎点

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

posted @ 2019-06-04 19:20  SeanOcean  阅读(622)  评论(0编辑  收藏  举报