寬度搜索

7-28 寬度搜索

           首先再次說明一下寬度搜索的概念與原理。寬度搜索,就是寬度優先搜索(也叫廣度優先搜索),所以寬度是優先。我們都知道深度搜索是一下子搜到底,然後再通過回溯之類的方式返回到上一個分支,然後繼續往下搜。也就是深度優先;而寬度優先搜索就是一層一層地找:先找一層,記錄下來,然後繼續搜下一層。

      這時我們就需要兩個指針:headtailhead是頭指針,用來標記上一層的第一個。tail就是尾指針,用來標記當前的位置。head每移動一個,那就是到了某一個分支的開始點,然後就用一個循環訪問這個開始點的每一個分支,並用一個一位數組把它們記錄下來,然後在訪問跟head同一層的另外的開始點。這一層全部訪問完後,就訪問下一層的第一個。

寬度搜索 - 周正華 - 周正華的博客

 

具體拿這個圖講一下吧:首先head指向1tail指向2,。然後找到1的分支,然後這個分支記爲2,。然後在第B層繼續掃描下一個分支點,同時tail++,將尾指針的位置往後移,用數組記錄,繼續掃3。掃完3後,B層的所有分支都掃完了,然後就到了C層……以此類推。

寬搜就是每搜一層就處理一次,那樣就能非常容易地解決“最短路徑”“重複”之類的問題。還有,在處理大數據的時候,用深搜可能會超時;可是用寬搜,就會變得很快。所以,寬搜的優點還是蠻多的。

下面可以通過一個問題來展示出寬搜是如何實現的:

 

 

奇怪的電梯(lift

Time Limit:1000MS  Memory Limit:65536K
Total Submit:70 Accepted:40

Description

呵呵,有一天我做了一個夢,夢見了一種很奇怪的電梯。大樓的每一層樓都可以停電梯,而且第i層樓(1<=i<=N)上有一個數字Ki(0<=Ki<=N)。電梯只有四個按鈕:開,關,上,下。上下的層數等於當前樓層上的那個數字。當然,如果不能滿足要求,相應的按鈕就會失靈。例如:3 3 1 2 5代表了Ki(K1=3,K2=3,……),從一樓開始。在一樓,按可以到4樓,按是不起作用的,因爲沒有-2樓。那麼,從A樓到B樓至少要按幾次按鈕呢?

Input

輸入文件共有二行,第一行爲三個用空格隔開的正整數,表示N,A,B(1≤N≤200, 1≤A,B≤N),第二行爲N個用空格隔開的正整數,表示Ki

Output

輸出文件僅一行,即最少按鍵次數,若無法到達,則輸出-1

Sample Input

5 1 5
3 3 1 2 5

Sample Output

3

 

下面是程序:

#include <iostream>

using namespace std;

 

long long N,A,B;

long long a[201];

bool pd,f[2001];

long long head=1,tail=2;

long long now[2001],step[2001];

void bfs();

 

int main()

{

      cin>>N>>A>>B;

      if(A==B)

      {

           cout<<0<<endl;

           return 0;

      }

      int x;

      for(int i=1;i<=N;i++)

           cin>>a[i];

      bfs(); 

      if(!pd)

           cout<<-1<<endl;

     

      return 0;

}

 

void bfs()

{

      now[1]=A;

      step[1]=0;

      f[A]=true;

      for(;head<=tail;head++)

      {

if((now[head]-a[now[head]])>0 && !f[(now[head]-a[now[head]])])

           {

                 now[tail]=now[head]-a[now[head]];

                 step[tail]=step[head]+1;

                 f[now[tail]]=true;

                 if(now[tail]==B)

                 {

                      pd=true;

                      cout<<step[tail]<<endl;

                      return ;

                 }

                 tail++;

           }

          

             if((now[head]+a[now[head]])<=N && !f[(now[head]+a[now[head]])])

           {

                 now[tail]=now[head]+a[now[head]];

                 step[tail]=step[head]+1;

                 f[now[tail]]=true;

                 if(now[tail]==B)

                 {

                      pd=true;

                      cout<<step[tail]<<endl;

                      return ;

                 }

                 tail++;

           }         

      }

      return ;

}

我們來看一下這個程序(關鍵是在bfs這部分)。首先定義了一個head頭指針與一個tail尾指針。tail指針記錄所在的結點,而head指針就是來記錄tail指針結點的上一個分支。這樣就可以通過數組中下標爲tail的元素繼承下標爲head的元素中的內容,如步數、時間、方位等:即step[tail]=step[head]+1。當tail找不到分支時,就會停止加1,那麼head指針跟上tail指針時,也就是全圖已經掃描過一遍了,那就停止搜索。

      需要注意的是:數組中以head爲下標的元素必須初始化(即step[1]=0,不然的話就會讓這個搜索毫無用處,可能還會導致死循環。

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