acm算法总结——搜索

一.搜索算法的概念及其种类:

1.概念:

利用计算机的高效性,穷举出问题的部分或者所有的解,是求解问题的一种方法。本质上是通过初始条件扩展出问题的“解答树”,去寻找问题的解。构建这样的树形模型主要由两个部分——控制结构(扩展节点的方式)和产生系统(扩展节点)。通过对每个节点不同方式的拓展去寻找目标解。 在这里插入图片描述

2.种类:

  1. 深度优先搜索(DFS)
  2. 广度优先搜索(BFS)
  3. 二分搜索
  4. 散列法(Hash)

二.算法实例:

1.深度优先搜索 :

深度优先搜索可用递归实现,深度优先搜索和回溯法类似都属于穷举搜索,只是回溯大多可以写在dfs中,只是回溯法需要返回上一结点的状态,判断是否使用深度优先搜索需要考虑的因素有:

  1. 是否可以通过列出所有答案求解。
  2. 是否可以找到限制条件进行剪枝。

基础模板

void dfs()//参数用来表示状态  
{  
    if(到达终点状态)  
    {  
        ...//根据题意添加  
        return;  
    }  
    if(越界或者是不合法状态)  
        return;  
    if(特殊状态)//剪枝
        return ;
    for(扩展方式)  
    {  
        if(扩展方式所达到状态合法)  
        {  
            修改操作;//根据题意来添加  
            标记;  
            dfs();  
            (还原标记)//是否还原标记根据题意  
            //如果加上(还原标记)就是 回溯法  
        }  
    }  
}  

例题

#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int n,C[15],vis[3][30],tot;//三个标记分别记录列,主对角线,副对角线 
void init()
{
   memset(C,0,sizeof(C));
   memset(vis,0,sizeof(vis));
   tot=0;
}
void dfs(int cur)
{
   if(cur==n) {
       if(tot<3)
       {
           for(int i=0;i<n;i++)
           printf("%d ",C[i]+1);
           printf("\n");
 }
    tot++;
}
   else
       for(int i=0;i<n;i++) {
           if(!vis[0][i]&&!vis[1][i+cur]&&!vis[2][cur-i+n])//每条主对角线行+列相等,每条副对角线行-列相等 
           {
               C[cur]=i;
               vis[0][i]=vis[1][i+cur]=vis[2][cur-i+n]=1;
               dfs(cur+1);
               vis[0][i]=vis[1][i+cur]=vis[2][cur-i+n]=0;//一定要还原,回溯的基本操作 
           } 
       }
}
int main()
{
    while(scanf("%d",&n)!=EOF){
         init();
         dfs(0);
         printf("%d",tot);
    }
   return 0;
} 
  • 素数环
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
int n,book[20],ans[20];
int isprime[40]={0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0};
void init(){
    memset(book,0,sizeof(book));
    memset(ans,0,sizeof(ans));
}
void dfs(int step){
    if(step==n)
    {
     if(isprime[ans[n-1]+ans[0]])
     {
      for(int i=0;i<n;i++)
       if(i!=n-1) 
              printf("%d ",ans[i]);
             else
              printf("%d",ans[i]);
         printf("\n");
  }
        return;
    }
    for(int i=2;i<=n;i++)
    {
        if(!book[i]&&isprime[i+ans[step-1]])
        {
            ans[step]=i;
            book[i]=1;
            dfs(step+1);
            book[i]=0;
        }
    }
}
int main()
{
 int t=1;
    while(scanf("%d",&n)!=EOF){
        init();
        printf("Case %d:\n",t++);
        if(n==1){
         printf("%d\n\n",1);
         continue;
  }
        ans[0]=1;
        book[1]=1;
        dfs(1);
        printf("\n");
    }
    return 0;
}
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int n,m,T,sx,sy,ex,ey,ans=0;
int mp[6][6],turn[4][2]={0,1,1,0,0,-1,-1,0};
void dfs(int x,int y)
{
    if(x==ex&&y==ey)
        ans++;
    else
    {
        int nx,ny;
        for(int i=0;i<4;i++)
        {
            nx=x+turn[i][0];
            ny=y+turn[i][1];
            if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&mp[nx][ny])
            {

                mp[nx][ny]=0;
                dfs(nx,ny);
                mp[nx][ny]=1;
            }
        }
    }
}
int main()
{
    memset(mp,1,sizeof(mp));
    scanf("%d%d%d%d%d%d%d",&n,&m,&T,&sx,&sy,&ex,&ey);
    for(int i=1;i<=T;i++)
    {
        int temp1,temp2;
        scanf("%d%d",&temp1,&temp2);
        mp[temp1][temp2]=0;
    }
    mp[sx][sy]=0;
    dfs(sx,sy);
    printf("%d",ans);
    return 0;
}

  • HDU Robot Motion(给定方向搜索类似模拟)
    在初始化book数组时,如果初始化为0,则对于一进入地图就是loop的数据就会出现错误,因为第一次经过入口时给入口的值为0,以至于检测是否循环时发生错误。以后对标记数组初始化时,将其初始化为-1
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int n,m,sy,book[15][15],answer1,answer2,flag=0;
char mp[15][15];
void dfs(int x,int y,int step)
{
   if(x<0||x>n-1||y<0||y>m-1)
   {
   	answer1=step;
   	return;
   }		
   if(book[x][y]!=-1)
   {
   	answer1=book[x][y];
   	answer2=step-book[x][y];
   	flag=1;
   	return;
   }
   book[x][y]=step;
   if(mp[x][y]=='N')
   	dfs(x-1,y,step+1);
   else if(mp[x][y]=='S')
   	dfs(x+1,y,step+1);
   else if(mp[x][y]=='W')
   	dfs(x,y-1,step+1);
   else if(mp[x][y]=='E')
   	dfs(x,y+1,step+1);
}
int main()
{
   while(scanf("%d%d%d",&n,&m,&sy),n!=0||m!=0||sy!=0)
   {
   	memset(book,-1,sizeof(book));
   	memset(mp,'0',sizeof(mp));
   	for(int i=0;i<n;i++)
   		scanf("%s",mp[i]);
   	dfs(0,sy-1,0);
   	if(flag)
   		printf("%d step(s) before a loop of %d step(s)\n",answer1,answer2);
   	else
   		printf("%d step(s) to exit\n",answer1);
   	answer1=answer2=flag=0;
   }
   return 0;
} 

2.广度优先搜素:

属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。它不同于深度优先的是,它是通过一个节点去拓展离它最近且满足条件的节点,逐层遍历,因此可以找到从初始状态到最终状态的路径。

基础模板:

void bfs(起始点) {
   将起始点放入队列中;
   标记起点访问;
   while (如果队列不为空) {
       访问队列中队首元素x;
       删除队首元素;
       for (x 所有相邻点) {
           if (该点未被访问过且合法) {
               将该点加入队列末尾;
           }
       }
   }
   队列为空,广搜结束;
}

例题:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章