深度优先搜索DFS:
①定义:是一种枚举所有完整路径以遍历所有情况的搜索方法。
②如何实现DFS:
使用栈较麻烦。
类比斐波那契数列,可以使用递归这种方式来实现DFS。使用递归系统会调用叫系统栈的东西存放递归中的每一层状态,本质还是栈实现。
③例子
(1)全排列(DFS思想)
求1 2 3或1 2 3 4全排列可以使用几个for循环解决,但当求1到n(n小于等于10)用for不能解决则利用递归。
#include <iostream>
using namespace std;
int n;
int book[20];//初始值为0
int res[20];
void dfs(int num){
if(num==n){
for(int i=0;i<n;i++){
cout<<res[i]<<" ";
}
cout<<endl;
return;
}
for(int i=1;i<=n;i++){
if(!book[i]){
book[i] =1;//标记
res[num] = i;
dfs(num+1);
book[i] = 0;//取消标记
}
}
}
int main(){
cin>>n;
dfs(0);
return 0;
}
(2)经典迷宫问题
题目链接:https://www.luogu.com.cn/problem/P1605
#include <bits/stdc++.h>
using namespace std;
int n,m,t,SX,SY,FX,FY,ans;
int Map[10][10];//为一表示走过或有障碍物
bool OK(int,int);
int dir[][2]={
{-1,0},//上
{0,1},//右
{1,0},//下
{0,-1},//左
};
bool OK(int x,int y){//保证坐标合法是否越界
return x>=1&&x<=n&&y>=1&&y<=n;
}
void dfs(int xx,int yy){
if(xx==FX&&yy==FY){
ans++;
return ;
}
for(int i=0;i<4;i++){
int nx = xx+dir[i][0];
int ny = yy+dir[i][1];
if(OK(nx,ny)&&!Map[nx][ny])//坐标合法并且没有障碍物并且没有走过,应该标记它
{
Map[nx][ny] = 1;
dfs(nx,ny);
Map[nx][ny]=0;
}
}
}
int main(){
cin>>n>>m>>t;
cin>>SX>>SY>>FX>>FY;//起点和终点
int x;int y;
while(t--){
cin>>x>>y;
Map[x][y] = 1;//标记为1
}
Map[SX][SY] = 1;//起点标记
dfs(SX,SY);
cout<<ans<<endl;
return 0;
}
广度优先搜索BFS:
①定义:到达岔口,先访问从岔道口能直接到达的所有结点,再按照这些结点被访问顺序依次访问它们能直接到达的所有结点,直到所有结点都被访问为止(类似水面石子落水形成的水波)。
②如何实现BFS:
一般由队列实现,总是按照层次的顺序遍历(层次遍历)。
连通块:一个图中任意两个结点之间都能相互到达。
如图:
③例子:
01迷宫(连通块+BFS算法)
题目链接:https://www.luogu.com.cn/problem/P1141
#include <bits/stdc++.h>
using namespace std;
int n,m;
bool OK(int,int);
int book[1010][1010];//标记数组初始值为0,
char Map[1010][1010];
struct Node{
int x,y;
Node(int xx,int yy){
x=xx;
y=yy;
}
};
//枚举的四种坐标
int dir[][2]={
{-1,0},//上
{0,1},//右
{1,0},//下
{0,-1}//左
};
bool OK(int xx,int yy){
return xx>=0&&xx<n&&yy>=0&&yy<n;
}
void BFS(int xx,int yy){
if(book[xx][yy]) return ;
queue<Node> q;
q.push(Node(xx,yy));
book[xx][yy] = 1;//起始点已经走过
vector<Node> v;//存连通块中有哪些节点
while(!q.empty()){//空则结束
Node t = q.front();q.pop(); //取对象坐标
v.push_back(t);
if(Map[t.x][t.y]=='0'){
for(int i=0;i<4;i++){
int nx = t.x+dir[i][0];
int ny = t.y+dir[i][1];
if(OK(nx,ny)&&Map[nx][ny]=='1'&&!book[nx][ny]){
book[nx][ny]=1;//标记访问
q.push(Node(nx,ny));//加入队列
}
}
}
else{
for(int i=0;i<4;i++){
int nx = t.x+dir[i][0];
int ny = t.y+dir[i][1];
if(OK(nx,ny)&&Map[nx][ny]=='0'&&!book[nx][ny]){
book[nx][ny]=1;//标记访问
q.push(Node(nx,ny));//加入队列
}
}
}
}
for(int i=0;i<v.size();i++){
book[v[i].x][v[i].y] = v.size();/*这里非0表示已经访问过了,
所以我这个book标记数组,记录是否访问过的同时记录答案 */
}
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>Map[i];
}
int x,y;
while(m--){
cin>>x>>y;
x--;y--;//输入从0开始
BFS(x,y);
cout<<book[x][y]<<endl;
}
return 0;
}