两天来学习搜索算法的小结

 

算法中需要使用搜索进行解决的内容很多,大致分为以下几类常用的搜索方式。

1、枚举。枚举运算量很大,需要预先确定枚举的定义域。

2、广度优先搜索(BFS )——通常可以用于计算图的连通性、单源最短路径、计算最小操作次数等。
3、深度优先搜索(DFS)——。经典题:火力中心布局。

 

BFS的占用的是队列的空间,DFS 占用的是栈的空间(因为递归)。BFS和DFS的空间复杂度恰好相反。对链状图,BFS最好(队列中最多只有1个元素),DFS最差(所有节点都在根节点的递归内)。对起点与其他所有点相邻的图,DFS最好(递归深度为1),BFS最差(队列中放满了所有与起点相邻的图)。

 

相对来说,BFS是比较简单的(恩,可能我做的水题)。

反正大致的模板就是

 

queue<type> q;

q.push(初始状态);

 

 while (!q.empty())

{

  type t = q.front() ;

  q.pop();

  遍历 t 的各个Next状态  next

  {

    if (next is legal)

      q.push(next); 计数或维护等;

  }

}

 

 但是BFS的状态数一多,需要的空间就会较大。因此就需要状态压缩,BUPT OJ上的1180就是一个典型的例子,但是状态压缩以及解压的时候,又会涉及效率,反正1180将80M的状态压缩到40K以后就超时了……

 

今天参考别人的代码,写了第一个DFS,POJ 1321。 相当的水。但是大牛的代码比我的简洁太多了。

DFS大致的模板就是

DFS(顶点)

{

  处理当前顶点,记录为已访问

  遍历与当前顶点相邻的所有未访问顶点

  {

      标记更改;

      DFS( 下一子状态);

      恢复更改;

  }

}

 

回溯法:DFS适用于 显式图,但是对于一些隐式关系,我们需要使用回溯法,通过定义或找到各个状态、边界条件、搜索范围、约束条件和最优解结果进行建模求解。

边界条件:达到某状态时,需要检查并确定是继续搜索还是回到上一状态的条件(例如当前已使用时间比当前最优解要长,此时就不需要再进行搜索)

搜索范围:当前从当前状态开始进行搜索的所有下一级状态。

搜索范围:

另外一定要注意,假如参与递归的参数不是通过传参形式的方式进入递归的话,那么一定要做好数据恢复。

Trace(当前状态)

{

    if 当前状态是结束状态

    {

         if 是最佳解: 记录。

         退出

    }

    遍历当前状态的各个邻接状态

    {

        if 当前状态满足约束条件 且 满足最优性要求 : Trace(子状态)

    }

}

 

回溯法经典题:任何大于1的自然数n,都可以拆分成若干个小于n的自然数之和,输入n,输出不同n的拆分方案。

 状态:对于一个拆分a1<=a2<=...a(k-1)<=ak, 下一拆分可以是 a1<=a2<=...a(k-1)<=m<=ak-m (其中a(k-1)<=m<=ak-m)


 

#include  < stdio.h >
#include 
< string .h >
#include 
< stdlib.h >

int  a[ 20 ];
int  result  =   0 ;
int  num;

void  Sum( int  kx)  // 传入参数为拆分结果的最后一项的位置
{
    result 
=  result  +   1 ;
    printf(
" %d\t%d =  " ,result,num);
    
for  (  int  i  =   1  ; i  <=  kx - 1  ; i ++ )
        printf(
" %d + " ,a[i]);
    printf(
" %d\n " ,a[kx]);
    
int  k  =  kx;
    
int  l  =  a[k];
    
for  ( int  m  =  a[k - 1 ]; m  <=  l / 2 ; m ++ )
    {
        a[k] 
=  m;
        a[k
+ 1  ]  =  l - m;
        Sum(k
+ 1 );
    }
}
int  main()
{
    
while ( 1 )
    {
        result 
=   0 ;
        scanf(
" %d " & num);
        
for  ( int  i  =   1  ; i  <  num; i ++ )
        {
            memset(a,
0 , sizeof (a));
            a[
1 =  i;
            a[
2 =  num - i;
            Sum(
2 );
        }
    }
    
return   0 ;
}

 

 

还有一个经典的题目是24点。

 

 

ExpandedBlockStart.gif View Code
 1  // 24 dian
 2 
 3  #include  < iostream >
 4  #include  < stdio.h >
 5  using   namespace  std;
 6 
 7  double  a[ 4 ];
 8  bool  b[ 4 ];
 9  double  ans;
10 
11  bool  judge( int  step)
12  {
13       if  (step  ==   3 )
14      {
15          if  ( a[ 3 -  ans  <  1e - 8   &&  a[ 3 -  ans  >   - (1e - 8 ))
16             return   true ;
17          else
18              return   false ;
19      }
20      
21       // else
22       for  (  int  j  =   0  ; j  <   3 ; j ++ )
23           for  ( int  i  =  j + 1 ; i  <   4 ; i ++ )
24          {
25               double  temp;
26               if  (  ! b[i]  &&   ! b[j])
27              {
28                   temp  =  a[i];
29                   b[j]  =   true ;
30                   
31                   a[i]  =  a[i]  +  a[j];
32                    if  (judge(step  +   1 ))  return   true ;
33                   a[i]  =  temp;
34                   
35                   a[i]  =  a[i]  -  a[j];
36                    if  (judge(step  +   1 ))  return   true ;
37                   a[i]  =  temp;
38                   
39                   a[i]  =  a[j]  -  a[i];
40                    if  (judge(step  +   1 ))  return   true ;
41                   a[i]  =  temp;
42                   
43                   a[i]  =  a[i]  *  a[j];
44                    if  (judge(step  +   1 ))  return   true ;
45                   a[i]  =  temp;
46                   
47                    if  ( a[j]  !=   0 )
48                   {
49                       a[i]  =  a[i]  /  a[j];
50                        if  (judge(step  +   1 ))  return   true ;
51                       a[i]  =  temp;
52                   }
53                   
54                    if  (a[i]  !=   0 )
55                   {
56                            a[i]  =  a[j]  /  a[i];
57                             if  (judge(step  +   1 ))  return   true ;
58                            a[i]  =  temp;
59                   }
60                   a[i]  =  temp;
61                   b[j]  =   false ;           // 回溯的时候要注意恢复现场
62              }
63          }
64      
65       return   false ;
66  }
67 
68  int  main()
69  {
70       while  (scanf( " %lf%lf%lf%lf%lf " & a[ 0 ], & a[ 1 ], & a[ 2 ], & a[ 3 ], & ans)  !=  EOF)
71      {
72             for  (  int  i  =   0  ; i  <   4 ; i ++ )
73                b[i]  =   false ;
74            
75             if  (judge( 0 ))
76               cout  <<   " Possible "   <<  endl;
77             else
78                cout  <<   " Impossible "   <<  endl;
79      }
80  }

 


 拓扑排序应该也能归到这里吧,通常都是使用优先队列这个imba的数据结构。

ExpandedBlockStart.gif View Code
// poj 1485 
#include  < stdio.h >
#include 
< vector >
#include 
< queue >
#include 
< string .h >

using   namespace  std;
const   int  N  =   100010 ;

// priority queue compare
struct  less_comp
{
       
bool   operator ()( const   int   & a,  const   int   & b)
       {
            
return  a  >  b;
       }
};

vector
< int >  vec[N];
int  n,k,indegree[N];
priority_queue
<   int , vector < int > , less_comp  >  q;

int  main()
{
    
int  n,k;
    
while (scanf( " %d%d " , & n, & k)  &&   ! (n == 0   &&  k == 0 ))
    {
        memset(indegree,
0 , sizeof (indegree));
        

        
int  first,last;
        
for  ( int  i  =   0  ; i  <  k ; i ++ )
        {
            scanf(
" %d%d " , & first, & last);
            vec[first].push_back(last);
            indegree[last]
++ ;
        }
        
        
//  get 0 degree
         for  ( int  i  =   1  ; i  <=  n ; i ++ )
        {
            
if  ( indegree[i]  ==   0 )
               q.push(i);
        }
        
        vector
< int > ::iterator it;
        vector
< int > ::iterator itend;
        
int  cur;
        printf(
" ORDER: " );
        
while ( ! q.empty())
        {
            cur 
=  q.top();
            q.pop();
            itend 
=  vec[cur].end();
            
for  (it  =  vec[cur].begin(); it  !=  itend; it ++ )
            {
                
if  ( -- indegree[ * it]  ==   0 )
                {
                    q.push(
* it);
                }
            }
            vec[cur].clear();
            printf(
"  %d " ,cur);
        }
        printf(
" \n " );
    }
}

 

不过目前还没有遇到剪枝之类的题目。还是需要多做水题消化消化。
 

转载于:https://www.cnblogs.com/HectorInsanE/archive/2010/11/09/1872656.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值