8【搜索專題】深度優先搜索和廣度優先搜索到底能幹啥?(例如:當你被困到迷宮裏,它能救你)

假設你想在被扔到了迷宮的入口(這裏的迷宮是樹形結構的迷宮,即每條分岔路之間不會互通,彼此相互獨立),你怎麼有邏輯地通過迷宮而不是兜兜轉轉呢?

有這樣一個方案:

①以入口爲起點,沿着任意一條路走,當遇到岔路口時選擇一條路進去,當再次遇到岔路口的時候選擇一條路再進去,不斷這樣進行下去。

②直到遇到牆壁無法走動的時候,退回到進入這條路的岔路口並選擇另一條岔路繼續走。以此類推,最終你會走過所有路徑(即遍歷),若有出口你就溜了。若沒有出口,你會最終會返回原點(並不是所有的迷宮都有出口,萬一有人給你做死局呢?)。

那上述這個方案在實際操作時如何做呢? 很簡單,從入口開始沿着你的右手的牆壁一直走就可以了。想象你在一個五角星裏面,沿着你的右手手臂(或者左手手臂)是不是就能夠轉一圈回到起點呢?

 

那我們如何將這個操作抽象成計算機的操作模型呢?我們需要把實際問題抽象成計算機語言中可以理解的內容。首先,死衚衕是路徑的終點,其次,在岔路口處我們需要進行選擇進入哪條路。比如起點有三條路A\B\C,進入A後又有3條路A11,A12,A13,而在A11中又有兩條路A21\22。 並且A12 A13,A21, A22,B,C,都是死衚衕,如圖所示。(這是一個沒有出口的迷宮,要打破思維僵化,誰說迷宮一定有出口,嘿嘿嘿)

我們從入口進入後會發現有三條路,這三條路當中,我們先後訪問的順序是A,A11,A21,A22,A12,A13, B。

通過觀察,我們發現,這種操作順序類似於棧。A入棧,A11入棧,A21入棧,此時到達死衚衕。A21出棧A22入棧,到達死衚衕,回到A11出棧,進入A12以此類推。

因此,我們可以用棧來實現這個遍歷。但是,我們仔細觀察可以發現,這個遍歷過程中棧的使用方式與我們遞歸中系統棧棧的使用流程很相似。我們舉個經典的斐波那契數列的例子來看一下。

Fibonacci數列的定義如下:F(0)=1,F(1)=1,....,F(n)=F(n-1)+F(n-2),我們把F(0)和F(1)比作死衚衕,F(n-1)和F(n-2)作爲兩個分支,這樣,整個遞歸的過程剛好與剛纔訪問的過程相同,因此我們可以用遞歸來實現上述走迷宮的過程(即深度優先遍歷)。

 

下面我們練習一個例子:

李華來到一座礦,假設現在有n塊規格各異的金子,每塊金塊的重量爲w[i],價值爲c[i]。現在小明需要選擇從中拿金塊,在保證重量不超過他的揹包的容量V的情況下,問揹包能夠裝的金塊的總價值最大是多少。

分析:我們可以把這個問題抽象爲遞歸問題,其中遞歸的兩個關鍵點即邊界條件(死衚衕),遞歸式(岔路口)。針對此題,每當遍歷到一件物品,把這件物品裝入書包和不裝入書包就是兩種選擇,就是此題中的岔路口。而當遍歷到最後一個金塊的時候,則說明到了結束條件。

因此,遞歸式子分爲兩個,一個是放入揹包,且重量和價值都要增加,一個是不放入揹包,重量個價值都不增加。在這個遍歷的過程中,用index通知遍歷到了第幾個金塊,當遍歷到最後一個金塊是,說明遍歷完成,更新當前滿足條件的最大值,並返回。最後求出結果。

#include<cstdio>
#include<iostream>
using namespace std;

const int maxn = 30;//定義常量:物品的最大數量,用於開數組
int n,V,maxValue=0;//定義物品件數、揹包容量、最大價值三個全局變量
int w[maxn],c[maxn];//w[i]爲每件物品的重量,c[i]爲每件物品的價值


//流程 1輸入當前物品編號、總重量、總價值
//2如果到達臨界值,即物品數量達到n,進入if語句
//如果當前最大值重量沒超重且總價值高於以統計的總價值,則更細最大價值,並在最後 return;
//然後遞歸循環左右分支,右分支代表加入該物品,左分支代表不加入該物品
//加入該物品的DFS需要增加重量、小標index和價值,不加入的不需要增加

void DFS(int index,int sumW,int sumC){
    if(index==n){
        if(sumW<=V&&sumC>maxValue){
            maxValue = sumC;
        }
        return;
    }

    DFS(index+1,sumW,sumC);
    DFS(index+1,sumW+w[index],sumC+c[index]);
}


int main(){
    scanf("%d%d",&n,&V);
    for(int i=0;i<n;i++){
        scanf("%d",&w[i]);//輸入每件物品的價值
    }
    for(int i=0;i<n;i++){
        scanf("%d",&c[i]);//輸入每件物品的價值
    }
    DFS(0,0,0);
    printf("%d\n",maxValue);
    return 0;


}

 

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