BFS / DFSの幅/深さ優先探索


深さ優先探索DFS

背中は見えないレンガの壁にヒットしていない - いわゆる深さ優先探索は、人気のポイントは、ヘッドが一方向に行きまし理解することです。

各充填、今123 3枚のカードの小さなハムの手を保持している、彼は3つのボックスには、この3枚のカードを与える、今度はフルに配置さ123で、完全な配列の問題を見てみましょうそれはまだ完全に配置されていないのですか?


しかし、毎回最後にカードが最初の1か3カードを入れて?

さて、私は順番に入れ、そして毎回順番1.2.3にカードを入れて、小さなと思います。そこで彼は、カードへの旧1号箱1に行ってきました箱の中にカード2前2号に行って、箱にカード3前第3号に行ってきましたが、少しハム...第四ボックスを来ましたカードが行われていると

フレンズ。その後、完全な配列「生まれた123」の友達を。

しかし、状況の良い品種は、ああ、そう彼は第3ボックスに戻ります前に、すぐに返すように小さなハム後者の完全な配列を持っているカード3を取得し、また、他のカードを入れていない参照してください、今小さなハムの手を明らかにすることがありますカード3に加えて、他の外部のカードは、これほど少ないハムが継続しないではありません

前に、2つの小さなハムが少しハムの手で2枚のカードを持っているカードを回収バック第2のボックスに行くので、彼はカード3号2箱を置き、その後、バックステップを取るために片付けスリーボックスは、カード2を入れ、トップ4はもちろん、ボックスに行っていません

第四にボックスは、ので、彼は完全な配列を生成「132

したがってシミュレーションによれば、それは順番に、フル構成「213」「231」「312」「321」を生成します

長い間、我々はそれを達成するためにコードを使用する方法を見て言いました

私はボックスの最初の段階にあるカードの枚数

for(i = 1; i <=n; i++)
    {
        a[step] = i;  //将卡片i放入第step个盒子里
    }

しかし、カードが他に箱に入れられているかの問題が、あります、あなたは現在のボックスを置くことはできません。そこで、我々はこのカードの手をマークするための本[]アレイがされて必要とします

for(i = 1; i <= n; i++)
    {
        if(book[i] == 0) / /如果手上有这张卡片
        {
            a[step] = i; //将卡片i放入第step个盒子里
            book[i] = 1; //此时手上已经没有这张卡了 标记一下
        }              
   }

最初のステップとして、我々は戻って一歩、第1の処理ステップ+ 1箱、+ 1箱と箱どうやら最初の処理ステップに行きたいステップボックスの方法を処理した後、我々はただの箱の最初のステップに対処します関数法として書か

void dfs(int step)
{
    for(i = 1; i <= n; i++)
        {
            if(book[i] == 0) / /如果手上有这张卡片
            {    
                a[step] = i; //将卡片i放入第step个盒子里
                book[i] = 1; //此时手上已经没有这张卡了 标记一下
            }              
       }
}

ライン上の処理工程+ 1つのボックスのみDFS(ステップ+ 1)

void dfs(int step)
{
    for(i = 1; i <= n; i++)
        {
            if(book[i] == 0) / /如果手上有这张卡片
            {    
                a[step] = i; //将卡片i放入第step个盒子里
                book[i] = 1; //此时手上已经没有这张卡了 标记一下
            }          
            dfs(step+1);//处理下个盒子
            book[i] = 0; //这步很重要!!往回走时要将之前的卡片收回!
       }
}

book[i] = 0;是将之前的卡片收回,如果不把刚才放入盒子的卡片收回,那么就无法再进行下一次摆放。
还剩最后一个问题,什么时候输出一个满足条件的序列呢?其实当我们走到第n+1个盒子前时,说明前n个盒子都已经放好卡片了,这时候我们就要return返回了


void dfs(int step)
{
    if (step == n + 1) //判断边界
    {
        for (i = 1; i <= n; i++)
            cout << a[i] << " ";
        cout << endl;
        return;//返回上一个盒子前
    }
    else
    {
        for (i = 1; i <= n; i++)
        {
            if (book[i] == 0) / /如果手上有这张卡片
            {
                a[step] = i; //将卡片i放入第step个盒子里
                book[i] = 1; //此时手上已经没有这张卡了 标记一下
            }
            dfs(step + 1);//处理下个盒子
            book[i] = 0; //这步很重要!!往回走时要将之前的卡片收回!
        }
    }
}

讲到这里想必大家已经对深度优先搜索有一定了解了吧,深搜使用就是递归和回溯的思想。

广度优先搜索BFS

讲完了dfs,我们再来看看什么是广度优先搜索。

所谓广度优先搜索就是一种层层递进的搜索。

我们来看一张图。这是一个迷宫,我们用一个二维数据储存它。

现在小哼站在(1 1)处,它可以向下或向右走,如何才能到达终点呢?已经学会深搜的你因该很快就想到办法了,但这里我们用另一种方法BFS,“一层层”扩展找到终点。扩展时每发现一个点就将这个点放入队列中,知道走到终点位置。和深搜一样,我们也需要一个book数组记录是否走过这个点。

我们每对一个点扩展完毕,这个点就没用了,所以要将这个点出队,对下个点扩展。

理解了这点后代码就很容易实现了^_^。

完整代码

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int x, y;
    int s;//步数
    int f;//父亲再队列中的编号
};

int main()
{
    queue<node> que;
    int a[51][51] = { 0 };
    int book[51][51] = { 0 };
    int next[4][2] =
    {
        {0,1}, //向右走
        {1,0},//向下走
        {0,-1},//向左走
        {-1,0}//向上走
    };
    int n, m, i, j, k, flag,p,q;
    node start, tnode;
    //输入迷宫的行列 起始点
    cin >> n >> m >> start.x >> start.y;
    //输入迷宫图
    for (i = 1; i <= n; i++)
        for (j = 1; j <= m; j++)
            cin >> a[i][j];
    cin >> p >> q;//输入终点
    book[start.x][start.y] = 1;//将起始点标记为走过
    //如果队列不为空
    while (!que.empty())
    {
        //枚举四个方向
        for (int k = 0; k <= 3; k++)
        {
            //计算下一步坐标
            tnode.x = que.front().x + next[k][0];
            tnode.y = que.front().y + next[k][1];
            //判断是否出界
            if (tnode.x<1 || tnode.x>n || tnode.y<1 || tnode.y>m)
                continue;
            //判断是否是陆地或已经走过
            if (mapp[tnode.x][tnode.y] > 0 && book[tnode.x][tnode.y] == 0)
            {
                sum++;
                //每个点只入队一次,标记走过
                book[tnode.x][tnode.y] = 1;
                int ts = que.back().s;//记录父亲的步数
                //将该点入队
                que.push(tnode);
                que.back().s = ts+1; //步数是父亲步数加1
            }
            if (tnode.x == p && tnode.y == q)
            {
                flag = 1;
                break;
            }
        }
        if (flag == 1)
            break;
        que.pop();//队首出队
    }

    cout << que.back().s << endl;
    system("pause");
    return 0;
}

练习

学完DFS和BFS后来练习一下吧。

题目:宝岛探索

小哼通过一种秘密方法得到一张不完整的钓鱼岛航拍图。小哼决定去钓鱼岛探险。

下面的10*10的矩阵就是该航拍图。图中数字表示海拔,0表示海洋,1-9都表示陆地。

小哼的飞机会降落再(6,8),现在需要计算小哼降落岛的面积。此处我们把降落点上

下左右相邻岛视为同一岛屿。

输入

输出

BFS代码如下:

#include<bits/stdc++.h>
using namespace std;

struct node
{
    int x;
    int y;
};
int main()
{
    queue<node> que;
    int mapp[51][51];
    int book[51][51];
    int i, j, n, m,sum;
    node start, tnode;
    memset(book, 0, sizeof(book));
    memset(mapp, 0, sizeof(mapp));
    //输入地图的行列,初始坐标
    cin >> n >> m >> start.x >> start.y;
    //输入地图
    for(i=1;i<=n;i++)
        for (j = 1; j <= m; j++)
        {
            cin >> mapp[i][j];
        }
    int next[4][2]=
    {
        {0,1}, //向右走
        {1,0},//向下走
        {0,-1},//向左走
        {-1,0}//向上走
    };
    //向队列插入降落的起始坐标
    que.push(start);
    sum = 1;
    book[start.x][start.y] = 1;
    //当队列不为空时循环
    while (!que.empty())
    {
        //枚举四个方向
        for (int k = 0; k <= 3; k++)
        {
            //计算下一步坐标
            tnode.x = que.front().x + next[k][0];
            tnode.y= que.front().y + next[k][1];
            //判断是否出界
            if (tnode.x<1 || tnode.x>n || tnode.y<1 || tnode.y>m)
                continue;
            //判断是否是陆地或已经走过
            if (mapp[tnode.x][tnode.y] > 0 && book[tnode.x][tnode.y] == 0)
            {
                sum++;
                //每个点只入队一次,标记走过
                book[tnode.x][tnode.y] = 1;
                //将该点入队
                que.push(tnode);
            }
            
        }
        //队首出队,下个点继续搜素
        que.pop();
    }
    cout << sum << endl;
    getchar();
    getchar();
    return 0;
}

DFS代码如下:

#include<bits/stdc++.h>
using namespace std;

struct node
{
    int x;
    int y;
};
int mapp[51][51];
int book[51][51];
int n, m,sum;
void dfs(int x,int y)
{
    int next[4][2] =
    {
        {0,1}, //向右走
        {1,0},//向下走
        {0,-1},//向左走
        {-1,0}//向上走
    };
    int tx, ty, k;
    //枚举四个方向
    for (k = 0; k <= 3; k++)
    {
        tx = x + next[k][0];
        ty = y + next[k][1];
        //判断是否出界
        if (tx<1 || tx>n || ty<1|| ty>m)
            continue;
        //判断是否是陆地或已经走过
        if (mapp[tx][ty] > 0 && book[tx][ty] == 0)
        {
            sum++;
            //标记走过
            book[tx][ty] = 1;
            dfs(tx, ty); //执行下一步
        }
    }
    return;
}
int main()
{
    
    int i, j,sx,sy;
    memset(book, 0, sizeof(book));
    memset(mapp, 0, sizeof(mapp));
    cin >> n >> m >> sx >> sy;
    //输入地图
    for(i=1;i<=n;i++)
        for (j = 1; j <= m; j++)
        {
            cin >> mapp[i][j];
        }
    book[sx][sy] = 1;
    sum = 1;
    dfs(sx, sy);
    cout << sum << endl;
    getchar();
    getchar();
    return 0;
}

拓展:如何求有多少个独立岛屿呢?

即求独立子图的个数,这就是Floodfill漫水填充法,又叫种子填充法。Windows下“画图”中的油漆桶工具就是基于这个算法的。
我们将独立岛屿进行染色,所以增加参数color。
代码如下

#include<bits/stdc++.h>
using namespace std;

struct node
{
    int x;
    int y;
};
int mapp[51][51];
int book[51][51];
int n, m,sum;
void dfs(int x,int y,int color)
{
    mapp[x][y] = color;//表示小哼来过这个岛
    int next[4][2] =
    {
        {0,1}, //向右走
        {1,0},//向下走
        {0,-1},//向左走
        {-1,0}//向上走
    };
    int tx, ty, k;
    //枚举四个方向
    for (k = 0; k <= 3; k++)
    {
        tx = x + next[k][0];
        ty = y + next[k][1];
        //判断是否出界
        if (tx<1 || tx>n || ty<1|| ty>m)
            continue;
        //判断是否是陆地或已经走过
        if (mapp[tx][ty] > 0 && book[tx][ty] == 0)
        {
            sum++;
            //标记走过
            book[tx][ty] = 1;
            dfs(tx, ty,color); //执行下一步
        }
    }
    return;
}
int main()
{
    
    int i, j,sx,sy,color=0;
    memset(book, 0, sizeof(book));
    memset(mapp, 0, sizeof(mapp));
    cin >> n >> m ;
    //输入地图
    for(i=1;i<=n;i++)
        for (j = 1; j <= m; j++)
        {
            cin >> mapp[i][j];
        }
    //对每个大于0(未被染色)的点尝试dfs染色
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= m; j++)
        {
            if (mapp[i][j] > 0)//如果没被染色
            {
                color--;//color减一表示一种新的颜色
                book[i][j] = 1; //标记走过
                dfs(i, j, color);
            }
        }
        
    }
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= m; j++)
        {
            cout<<mapp[i][j]<<" ";
        }
        cout << endl;
    }
    cout <<"共有独立岛屿:"<< -color<<" 个" << endl;
    getchar();
    getchar();
    return 0;
}

おすすめ

転載: www.cnblogs.com/muyefeiwu/p/11315482.html