引言:经过上一次的学习,我们明白了图的基本操作。这一次,我们学习图的两种基本算法——bfs与dfs。
图的遍历
1.dfs算法
介绍:dfs算法也叫深度优先搜索,核心思想是从某一位置或者状态出发,进行搜索,直到找到为止。形象的可以认为是所有的可能都走一边,既暴力。
深度优先遍历图的方法是,从图中某顶点v出发:
(1)访问顶点v;
(2)依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
(3)若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。
(一)dfs模板
void dfs(写入的参数)
{
if(条件符合要求)
{
进行相关的操作(比如输出,计数等)
return ;//结束操作
}
循环遍历每一种可能,进行相关的操作
{
if(这种方式没有进行)
{
标记;
进行;
dfs(参数改变);
回溯;
}
}
}
(二)例题
下面给出一道相关的例题:
排列数字
给定一个整数n,将数字1~n排成一排,将会有很多种排列方法。
现在,请你按照字典序将所有的排列方法输出。
Input
共一行,包含一个整数n。
Output
按字典序输出所有排列方案,每个方案占一行。
Input
3
Output
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
这道题我们就可以使用dfs算法来完成:
#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
const int N=1e5+3;
int n,m,j,k,l;
int s[N];
bool st[N];
void dfs(int k)
{
if(k==n)
{
for(int i=0;i<n;i++)
cout<<s[i]<<" ";
puts("");
return ;
}
for(int i=1;i<=n;i++)
{
if(st[i]==false)
{
s[k]=i;
st[i]=true;
dfs(k+1);
st[i]=false;
}
}
}
int main()
{
cin>>n;
dfs(0);//从0开始遍历
return 0;
}
2.bfs算法
简介:bfs又叫广度优先搜索,主要使用队列来完成某些操作
广度优先搜索使用队列来实现,整个过程也可以看做一个倒立的树形:
1、把根节点放到队列的末尾。
2、每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。
3、找到所要找的元素时结束程序。
4、如果遍历整个树还没有找到,结束程序。
(一)bfs模板
注:模板不一定唯一
#include <queue>//这里我们使用STL
const int N=103;
int st[N][N]={0};
typedef struct node
{
int x;
int y;
}list;//定义结构体,用来存放点或者其他
//定义方向数组
int dx[4]={1,0,-1,0};
int dy[4]={0,-1,0,1};
queue<list>q;//定义队列
void bfs(参数)
{
list s;
st[0][0]=1;
q.push(list p);
while(!q.empty())
{
s=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int a=s.x+dx[i];
int b=s.y+dy[i];
if(条件如果成立)
{
list ss;
ss.x=a;
ss.y=b;
q.push(ss);
st[a][b]=st[s.x][s.y]+1;
}
}
}
进行最后的相关操作;
}
(二)例题
走迷宫
给定一个n*m的二维整数数组,用来表示一个迷宫,数组中只包含0或1,其中0表示可以走的路,1表示不可通过的墙壁。
最初,有一个人位于左上角(1, 1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角(n, m)处,至少需要移动多少次。
数据保证(1, 1)处和(n, m)处的数字为0,且一定至少存在一条通路。
Input
第一行包含两个整数n和m。
接下来n行,每行包含m个整数(0或1),表示完整的二维数组迷宫。
Output
输出一个整数,表示从左上角移动至右下角的最少移动次数。
Input
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
Output
8
#include <iostream>
#include <algorithm>
#include <queue>
#include <string.h>
using namespace std;
const int N=103;
typedef pair<int,int> pii;
int n,m;
int a[N][N],b[N][N];
void bfs()
{
memset(b,-1,sizeof(b));
b[0][0]=0;
queue<pii> q;
q.push({0,0});
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
while(!q.empty())
{
pii t=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int x=dx[i]+t.first;
int y=dy[i]+t.second;
if(x<0||y<0||x>=n||y>=m||b[x][y]!=-1||a[x][y]!=0)
{
continue;
}
q.push({x,y});
b[x][y]=b[t.first][t.second]+1;
}
}
cout<<b[n-1][m-1]<<endl;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>a[i][j];
}
bfs();
return 0;
}
后记
学习这两算法时候,确实耗费了不少时间与精力。每每回想过去一点点的进步,便有了继续下去的动力。数据结构部分可以说是告一段落了,下次就是算法部分。希望大家可以给出更好的意见。