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;


}

 

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