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 (該點未被訪問過且合法) {
               將該點加入隊列末尾;
           }
       }
   }
   隊列爲空,廣搜結束;
}

例題:

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