搜索与数据结构


最简单的搜索当然分为两种,深度优先搜索和广度优先搜索。这两种算法分别采用了栈和队列的数据结构来实现。对于深搜,优化方法通常是各种剪枝,主要包括最优化剪枝和可行性剪枝。对于广搜,优化方式通常是进行重复去除和优先搜索。

通常都说能用深搜不用广搜,其实在一定条件下确实有道理。在很多情况下,深度优先搜索通常比广度优先搜索写起来简单、方便。同时,采用简单的递归方法来描述深度优先搜索,可以避开对数据结构的操作。同时,深度优先搜索不需要一个巨大的队列来记录,因此可以节约内存。但使用深度优先搜索需要合理并且足量的剪枝才能完成。

本文对这些内容分别进行讨论和整理。因水平较低,有不尽之处欢迎各位批评指正。

深度优先搜索

深度优先搜索遵循深度优先,遇阻回溯的原则,可以构造出如下的伪代码。

void dfs(int depth)
{

if(出现问题) return;

if(到达终点) ……

if(满足剪枝条件) ……
else 处理数据;dfs(depth+1);
return;
}

典型样例:N皇后问题

这是一个很典型的深度优先搜索问题。套用上面的规程,(出现问题)就是验证是否有两个皇后互相可以干扰,(到达终点)就开始输出,此题无需进一步剪枝,处理数据就是对皇后摆放位置的循环。

#include 
  
  
   
   
#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
        #define llat(x) ll[x+50] #define lrat(x) lr[x+50] using namespace std; char a[14]; char uCr[14]; char ll[100],lr[100]; int cnt=0; int n=0; int dfs(char line) { char i,j; if(line==n) { cnt++; if(cnt<=3) { for(i=0;i 
       
         >n; memset(a,0,sizeof(a)); memset(uCr,0,sizeof(uCr)); memset(ll,0,sizeof(ll)); memset(lr,0,sizeof(lr)); dfs(0); cout< 
        
          < 
          
         
        
      
     
     
    
    
   
   
  
  


广度优先搜索

广度优先搜索遵循层层遍历,存取队列的原则,可以构造出如下的伪代码

void bfs()

{

for(循环条件)

{

数据处理;

if(重复)continue;

if(满足终点条件)……;

else queue.push(……);

}

return;

}

典型样例:马的遍历问题

这是一个很典型的广度优先搜索的问题。套用伪代码,我们通过一个for循环来从当前坐标向着8个可到达的点扩展。如果扩展后遍历成功,就输出;未成功就判断是否重复,不重复就压入队列。一次for结束后从队列中pop一个坐标出来,然后继续。

需要注意的是,本题有几个可以优化的地方(下面的参考代码中可能未给出)

1.储存坐标的时候,很多认为需要使用结构体储存,这样固然是一种方法,但是写起来麻烦,有时浪费内存。一种偷懒的方法,就是利用坐标<10000的原理,将x*10000+y这样一个整数来表示坐标。其实就是运用了二维图像映射到一维内存的原理。

2.去重的时候常用bool数组。其实如果需要的话使用bit压缩在很大程度上能降低check()的时间复杂度,而且节约内存。

#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
using namespace std;
int a[205][205];
int n,m,sx,sy;
int oi[8]={-2,-1,1,2,2,1,-1,-2};
int oj[8]={1,2,2,1,-1,-2,-2,-1};
int check()
{
    int i,j;
    for(i=0;i
        
        
          >n>>m>>sx>>sy; --sx;--sy; int i=-1,j=-1,l,cnt=0;; queue 
         
           vi;queue 
          
            vj; vi.push(sy);vj.push(sx); while(check()) { cnt++; if(cnt>n*10)break; vi.push(-1);vj.push(-1); while((!vi.empty())&&vi.front()!=-1) { i=vi.front();j=vj.front(); vi.pop();vj.pop(); for(l=0;l<=7;l++) if(a[i+oi[l]][j+oj[l]]==0&&i+oi[l]>=0&&i+oi[l] 
           
             =0&&j+oj[l] 
             
            
           
          
        
       
       
      
      
     
     
    
    

典型错误与优化建议

1.刷表是记忆化搜索思想的一种实现,有时能起到极大的时间复杂度降低的作用,在很多题目中都得以体现。
(待更新


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值