两个吃奶一个添下面视频_人妻第一页香蕉网_欧美xxxx少妇_妺妺窝人体色www婷婷

本篇將會結(jié)合實例解析寬度優(yōu)先搜索(BFS)。


一、BFS概念

寬度優(yōu)先搜索算法(又稱廣度優(yōu)先搜索)是最簡便的圖的搜索算法之一,這一算法也是很多重要的圖的算法的原型。Dijkstra單源最短路徑算法和Prim最小生成樹算法都采用了和寬度優(yōu)先搜索類似的思想。其別名又叫BFS,屬于一種盲目搜尋法,目的是系統(tǒng)地展開并檢查圖中的所有節(jié)點,以找尋結(jié)果。換句話說,它并不考慮結(jié)果的可能位置,徹底地搜索整張圖,直到找到結(jié)果為止。

所謂廣度,就是一層一層的,向下遍歷,層層堵截,還是這幅圖,我們?nèi)绻菑V度優(yōu)先遍歷的話,我們的結(jié)果是V1 V2 V3 V4 V5 V6 V7 V8。

(1)訪問頂點vi ;

(2)訪問vi 的所有未被訪問的鄰接點w1 ,w2 , …wk ;

(3)依次從這些鄰接點(在步驟②中訪問的頂點)出發(fā),訪問它們的所有未被訪問的鄰接點; 依此類推,直到圖中所有訪問過的頂點的鄰接點都被訪問;


二、BFS(廣度優(yōu)先搜索)

廣度優(yōu)先搜索較之深度優(yōu)先搜索之不同在于,深度優(yōu)先搜索旨在不管有多少條岔路,先一條路走到底,不成功就返回上一個路口然后就選擇下一條岔路,而廣度優(yōu)先搜索旨在面臨一個路口時,把所有的岔路口都記下來,然后選擇其中一個進入,然后將它的分路情況記錄下來,然后再返回來進入另外一個岔路,并重復這樣的操作,用圖形來表示則是這樣的。

BFS(廣度優(yōu)先搜索)1

從黑色起點出發(fā),記錄所有的岔路口,并標記為走一步可以到達的。然后選擇其中一個方向走進去,我們走黑點方塊上面的那個,然后將這個路口可走的方向記錄下來并標記為2,意味走兩步可以到達的地方。

BFS(廣度優(yōu)先搜索)2

接下來,我們回到黑色方塊右手邊的1方塊上,并將它能走的方向也記錄下來,同樣標記為2,因為也是走兩步便可到達的地方。

BFS(廣度優(yōu)先搜索)3

這樣走一步以及走兩步可以到達的地方都搜索完畢了,下面同理,我們可以迅速把三步的格子給標記出來。

BFS(廣度優(yōu)先搜索)3

再之后是四步,五步。

寬度優(yōu)先搜索算法

我們便成功尋找到了路徑,并且把所有可行的路徑都求出來了。在廣度優(yōu)先搜索中,可以看出是逐步求解的,反復的進入與退出,將當前的所有可行解都記錄下來,然后逐個去查看。在DFS中我們說關鍵點是遞歸以及回溯,在BFS中,關鍵點則是狀態(tài)的選取和標記。


三、例題

(1)題目一:

一位農(nóng)夫在點n上,他要到奶牛所在的點k上,他可以每次從點X到點X-1或點X+1或點2*X,問他到達點k的最短次數(shù).(0 ≤ N ≤ 100,000,0 ≤ K ≤ 100,000)

樣例:

Sample Input

5 17

Sample Output

4

思路:看到這一道題,第一反應就是看看能否找到規(guī)律,然而很顯然它沒有規(guī)律可言,我們需要靠一種近似暴力的方法,而DFS在這里是行不通的,于是只能用BFS來解這道題了。

代碼如下:

#include <iostream>
#include <stdio.h>
#include <cstring>
#include<queue>
#define pp pair<int,int>
using namespace std;
int n,k,ans;
queue<pp>q;
bool v[200004];
void bfs() {
    q.push(pp(n,0));//先將n丟進隊列
    v[n]=1;
    while(!q.empty()) {
        if(q.empty())break;
        pp now=q.front();
        q.pop();
        if(now.first==k) {
            ans=now.second;
            break;
        }
        now.second++;//接下來我們有3種操作,將現(xiàn)在的位置now.second 加1 或 減1 或 乘2
        if(!v[now.first+1]&&now.first<k) {//邊界條件不能少了
            q.push(pp(now.first+1,now.second));
            v[now.first+1]=1;//將已經(jīng)走過的點標記為1,為什么呢??q隊列中到這個數(shù)的次數(shù)是從小到大排序的,now.first+1這個點剛通過now.first被拜訪過,它的此時次數(shù)肯定小于等于下一次拜訪的次數(shù).想一想為什么.
        }
        if(!v[now.first-1]&&now.first-1>=0) {
            q.push(pp(now.first-1,now.second));
            v[now.first-1]=1;
        }
        if(now.first<k&&(!v[now.first*2])) {
            q.push(pp(now.first*2,now.second));
            v[now.first*2]=1;
        }
    }
    return;
}
int main() {
    scanf("%d%d",&n,&k);
    bfs();
    printf("%d\n",ans);
    return 0;
}

(2)題目二:

給你兩個四位數(shù)的質(zhì)數(shù)a,b,讓你通過一個操作使a變成b.這個操作可以使你當前的數(shù)x改變一位上的數(shù)使其變成另一個質(zhì)數(shù),問操作的最小次數(shù)(如果沒有這種方式,輸出Impossible)

注意:沒有前導0!!!;

例如:1033到8179可以從1033->1733->3733->3739->3779->8779->8179

樣例:

Sample Input

3

1033 8179

1373 8017

1033 1033

Sample Output

6

7

0

思路:可以先將10000以內(nèi)所有的質(zhì)數(shù)記錄下來,再進行BFS。

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<queue>
#include<time.h>
#define N 10003
#define pp pair<int,int>
using namespace std;
int T,n,m,ans;
bool v[N],vis[N],t[N];
queue<pp>q;
void pre() {//記錄10000以內(nèi)的質(zhì)數(shù)
    for(int i=2; i<=9999; i++) {
        if(!v[i]) {
            t[i]=1;//t[i]=1表示i是質(zhì)數(shù)
            for(int j=i; j<=9999; j+=i) {
                v[j]=1;
            }
        }
    }
}
void BFS() {
    q.push(pp(n,0));//先將給我們的初始數(shù)加入q隊列
    while(!q.empty()) {
        while(!q.empty()&&vis[q.front().first])q.pop();
        if(q.empty())break;
        pp now=q.front();
        vis[q.front().first]=1;
        q.pop();
        if(now.first==m) {
            ans=now.second;
            break;
        }
        for(int i=1; i<=1000; i*=10) {//枚舉位數(shù)
            int r=now.first-((now.first/i)%10)*i;
            for(int j=0; j<=9; j++) {//枚舉當前位數(shù)更改的值
                if(i==1000&&j==0)continue;//特判前導0的情況!!!
                if(t[r+j*i]&&!vis[r+j*i]) {
                    q.push(pp(r+j*i,now.second+1));//BFS的核心轉(zhuǎn)移代碼
                }
            }
        }
    }
    return;
}
int main() {
    pre();
    scanf("%d",&T);
    while(T--) {
        while(!q.empty())q.pop();
        memset(vis,0,sizeof vis);
        ans=-1;
        scanf("%d%d",&n,&m);
        BFS();
        if(ans==-1)printf("Impossible\n");
        else printf("%d\n",ans);
    }
    return 0;
}


點贊(0)

C語言網(wǎng)提供由在職研發(fā)工程師或ACM藍橋杯競賽優(yōu)秀選手錄制的視頻教程,并配有習題和答疑,點擊了解:

一點編程也不會寫的:零基礎C語言學練課程

解決困擾你多年的C語言疑難雜癥特性的C語言進階課程

從零到寫出一個爬蟲的Python編程課程

只會語法寫不出代碼?手把手帶你寫100個編程真題的編程百練課程

信息學奧賽或C++選手的 必學C++課程

藍橋杯ACM、信息學奧賽的必學課程:算法競賽課入門課程

手把手講解近五年真題的藍橋杯輔導課程

Dotcpp在線編譯      (登錄可減少運行等待時間)