区别与联系

区别

DFS多用于连通性问题因为其运行思想与人脑的思维很相似,故解决连通性问题更自然,采用递归,编写简便(但我个人不这样觉得。。。)

DFS的常数时间开销会较少。所以对于一些能用DFS就能轻松解决的,为何要用BFS?

一般来说,能用DFS解决的问题,都能用BFS

BFS多用于解决最短路问题,其运行过程中需要储存每一层的信息,所以其运行时需要储存的信息量较大,如果人脑也可储存大量信息的话,理论上人脑也可运行BFS。

Backtracking相当于在DFS的基础上进行剪枝。

联系

BFS(显式用队列)

DFS(隐式用栈)(即递归)

当然,对于DFS,用递归可能会造成栈溢出,所以也可以更改为显示栈。

模板

在解答树里进行考虑

DFS/Backtracking

 void dfs(int 当前状态)
{
if(当前状态为边界状态)
{
记录或输出
return;
}
for(i=;i<n;i++) //横向遍历解答树所有子节点
{
//扩展出一个子状态。
修改了全局变量
if(子状态满足约束条件)
{
dfs(子状态)
}
恢复全局变量//回溯部分
}
}

BFS

void bfs()
{
q.push(s); //将(起始)首节点加入队列
visited[s]=true; //标记首节点已经被访问
while(!q.empty())
{
int x=q.front();
q.pop();
遍历 x 的各个Next状态 next
{
if(next is legal)
q.push(next); //入队,同时计数或维护等;
}
}
}

DFS(非递归,显式用栈)

 //求(sx,sy)到(ex,ey)的其中一条路径
//如果无法到达,返回false
bool dfs()
{
stack<P>s;
vis[sx][sy] = true; //访问
s.push(P(sx, sy)); //入栈
while (!s.empty()) //栈不为空。继续搜索;为空了还没有得到路径,说明无解
{
P p = s.top();
int x = p.first, y = p.second;
if (x == ex && y == ey)
{
while (!s.empty())
{
//打印结果,或进行其它操作
P p = s.top(); s.pop();
printf("%d %d\n", p.first, p.second);
}
return true;
}
int flag = false; //记录是否进入“死胡同”
for(遍历相邻的状态)
{
if(满足条件)
{
vis[nx][ny] = true;
s.push(P(nx, ny));
flag = true;
break; //DFS,选择其中一条路走
}
}
if (!flag)
s.pop(); //周四是墙或已走过,回溯,也就是不断出栈,知道新的栈顶元素有其他出路
}
return false;
}

经典例题

部分和问题(DFS+剪枝)

给定整数a1、a2、...an,判断是否可以从中选出若干个数字,使它们的和恰好为k。(1≤n≤20)

 #include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std; const int maxn = + ;
int n, a[maxn], k;
int vis[maxn]; //已经从前cur项得到和sum
bool dfs(int cur, int sum)
{
if (sum > k) return false; //剪枝
if (cur == n) return sum == k; //如果前n项都计算过了,则返回sum是否等于k //不加上a[i]的情况
if (dfs(cur + , sum)) return true;
//加上a[i]的情况
if (dfs(cur + , sum + a[cur])) return true; //无论是否加上a[i]都不能凑成k,则返回false
return false;
} int main()
{
while (scanf("%d%d", &n, &k) == && n)
{
for (int i = ; i < n; i++)
scanf("%d", &a[i]);
if (dfs(, )) printf("YES\n");
else printf("NO\n");
}
return ;
}

若要求输出所有的方案

 #include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std; const int maxn = + ;
int n, a[maxn],k;
int vis[maxn],flag; bool dfs(int cur, int sum)
{
if (cur == n)
{
if (sum == k)
{
flag = ;
for (int i = ; i < n; i++)
if (vis[i]) printf("%d ", a[i]);
printf("\n");
}
return sum == k;
}
vis[cur] = false; //不加上a[cur]
dfs(cur + , sum); //这里不要return,都是在cur == n时(即遍历完了)在返回true/false vis[cur] = true; //加上a[cur]
dfs(cur + , sum + a[cur]);
} int main()
{
while (scanf("%d%d",&n,&k) == && n)
{
for (int i = ; i < n; i++)
scanf("%d", &a[i]);
flag = ;
dfs(, );
if (flag)
printf("Yes\n");
else printf("No\n");
}
}

联通块问题(DFS)

有一个大小为NxM的园子,雨后积起了水。八联通的积水被认为是连接在一起的。请求出园子里总共有多少个水洼?(N,M≤100)

 #include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std; const int maxn = + ;
const int maxm = + ;
const int dx[] = { -,,,,,,-,- };
const int dy[] = { ,,,,-,-,-, };
int N, M;
char field[maxn][maxm]; //现在位置(x,y)
void dfs(int x, int y)
{
field[x][y] = '.'; //表示已访问 for (int i = ; i < ; i++)
{
int nx = x + dx[i], ny = y + dy[i];
if (nx >= && nx < N && ny >= && ny < M && field[nx][ny] == 'W') dfs(nx, ny);
}
return;
} void slove()
{
int res = ; //记录联通块个数
for(int i = ;i < N;i++)
for (int j = ; j < M; j++)
{
if (field[i][j] == 'W')
{
dfs(i, j); //从有W的地方开始dfs,
res++;
}
}
printf("%d\n", res);
} int main()
{
while (scanf("%d%d",&N,&M) == && N)
{
for (int i = ; i < N; i++)
scanf("%s", field[i]);
slove();
}
return ;
}

最短路问题 (BFS)

给定一个大小为N x M的迷宫。迷宫由通道和墙壁组成,每步可以向邻接的上下左右四格的通道移动。请求出从起点到终点所需的最小步数。(N,M ≤ 100)

 #include<stdio.h>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std; typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int maxn = + ;
const int maxm = + ;
const int dx[] = { -,,, };
const int dy[] = { ,,,- };
int N, M;
int sx, sy; //起点
int ex, ey; //终点
char maze[maxn][maxm];
int d[maxn][maxm]; //起点到各个位置的最短距离的数组 //求(sx,sy)到(ex,ey)的最短距离
//如果无法到达,返回INF
int bfs()
{
queue<P>que;
for (int i = ; i < N; i++) //把所有位置初始化为INF
for (int j = ; j < M; j++)
d[i][j] = INF;
que.push(P(sx, sy)); //将起点加入队列,且将距离置为0
d[sx][sy] = ; while (!que.empty())
{
P p = que.front(); que.pop();
if (p.first == ex && p.second == ey) break; //如果到达终点,退出循环,由于bfs的特点,这时得到的就是最短距离 for (int i = ; i < ; i++)
{
int nx = p.first + dx[i], ny = p.second + dy[i];
if(nx >= && nx < N && ny >= && ny < M && maze[nx][ny] != '#' && d[nx][ny] == INF)
{
que.push(P(nx, ny));
d[nx][ny] = d[p.first][p.second] + ;
}
}
}
return d[ex][ey];
}
int main()
{
while (scanf("%d%d",&N,&M) == && N)
{
for (int i = ; i < N; i++)
scanf("%s", maze[i]);
for(int i = ;i < N;i++)
for (int j = ; j < M; j++)
{
if (maze[i][j] == 'S')
{
sx = i; sy = j;
}
if (maze[i][j] == 'G')
{
ex = i; ey = j;
}
}
int dis = bfs();
if (dis == INF) printf("no way\n");
else printf("%d\n", dis);
}
return ;
}

八皇后问题(Backtracking)

在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

  #include<stdio.h>
#include<iostream>
#include<cmath>
using namespace std;
const int N = ;
int map[N][N];
int cnt = ; //记录方案数 /************************打印结果********************/
void Display()
{
printf("--------------解决方案 %d :-------------\n",cnt);
for (int i = ; i < N; i++)
{
for (int j = ; j < N; j++)
{
if (map[i][j] == )
cout << '.';
else
cout << '#';
}
printf("\n");
}
} /*********************判断是否与前面冲突****************/
int Check(int row, int col)
{
int flag = ;
if (row == )
return true;
for (int i = ; i < row; i++)
{
for (int j = ; j < N; j++)
{
if (map[i][j] == )
if (j == col || (fabs(row-i) == fabs(col - j)))
flag = ;
}
}
return flag;
} /**************************按行深搜***********************/
void Dfs(int row)
{
if (row == N)
{
cnt++;
Display();
return;
}
for (int col = ; col < N; col++)
{
if (Check(row, col))
{
map[row][col] = ; //标记
Dfs(row + );
map[row][col] = ; //回溯,修改了的全局变量必须及时还原
}
}
return;
}
int main()
{
Dfs();
return ;
}

 迷宫历经问题(DFS非递归)给定一个大小为N x M的迷宫。迷宫由通道和墙壁组成,每一步可以向邻接的上下左右四格的通道移动。请求出起点到终点的任意一条路径,若无法到达,输出"no way"

 #include<stdio.h>
#include<iostream>
#include<stack>
#include<algorithm>
using namespace std; typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int maxn = + ;
const int maxm = + ;
const int dx[] = { -,,, };
const int dy[] = { ,,,- };
int N, M;
int sx, sy; //起点
int ex, ey; //终点
char maze[maxn][maxm];
bool vis[maxn][maxn]; //求(sx,sy)到(ex,ey)的其中一条路径
//如果无法到达,返回false
bool dfs()
{
stack<P>s;
vis[sx][sy] = true;
s.push(P(sx, sy)); while (!s.empty())
{
P p = s.top();
int x = p.first, y = p.second;
if (x == ex && y == ey)
{
while (!s.empty())
{
P p = s.top(); s.pop();
printf("%d %d\n", p.first, p.second);
}
return true;
}
int flag = false;
for (int i = ; i < ; i++)
{
int nx = x + dx[i], ny = y + dy[i];
if (nx >= && nx < N && ny >= && ny < M && maze[nx][ny] != '#' && vis[nx][ny] == false)
{
vis[nx][ny] = true;
s.push(P(nx, ny));
flag = true;
break; //DFS,选择其中一条路走
}
}
if (!flag)
s.pop(); //周四是墙或已走过,回溯,也就是不断出栈,知道新的栈顶元素有其他出路
}
return false;
}
int main()
{
while (scanf("%d%d", &N, &M) == && N)
{
for (int i = ; i < N; i++)
scanf("%s", maze[i]);
for (int i = ; i < N; i++)
for (int j = ; j < M; j++)
{
if (maze[i][j] == 'S')
{
sx = i; sy = j;
}
if (maze[i][j] == 'G')
{
ex = i; ey = j;
}
}
if (!dfs()) printf("no way\n");
}
return ;
}

参考链接:

https://www.zhihu.com/question/28549888

https://blog.csdn.net/fightforyourdream/article/details/12866861

https://blog.csdn.net/renwotao2009/article/details/52993277

https://blog.csdn.net/lalor/article/details/6845788

https://blog.csdn.net/HUSTLX/article/details/52163923

DFS、BFS和Backtracking模板的更多相关文章

  1. DFS/BFS+思维 HDOJ 5325 Crazy Bobo

    题目传送门 /* 题意:给一个树,节点上有权值,问最多能找出多少个点满足在树上是连通的并且按照权值排序后相邻的点 在树上的路径权值都小于这两个点 DFS/BFS+思维:按照权值的大小,从小的到大的连有 ...

  2. 【DFS/BFS】NYOJ-58-最少步数(迷宫最短路径问题)

    [题目链接:NYOJ-58] 经典的搜索问题,想必这题用广搜的会比较多,所以我首先使的也是广搜,但其实深搜同样也是可以的. 不考虑剪枝的话,两种方法实践消耗相同,但是深搜相比广搜内存低一点. 我想,因 ...

  3. ID(dfs+bfs)-hdu-4127-Flood-it!

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4127 题目意思: 给n*n的方格,每个格子有一种颜色(0~5),每次可以选择一种颜色,使得和左上角相 ...

  4. [LeetCode] 130. Surrounded Regions_Medium tag: DFS/BFS

    Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. A reg ...

  5. HDU 4771 (DFS+BFS)

    Problem Description Harry Potter has some precious. For example, his invisible robe, his wand and hi ...

  6. DFS/BFS视频讲解

    视频链接:https://www.bilibili.com/video/av12019553?share_medium=android&share_source=qq&bbid=XZ7 ...

  7. POJ 3083 -- Children of the Candy Corn(DFS+BFS)TLE

    POJ 3083 -- Children of the Candy Corn(DFS+BFS) 题意: 给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走 1)先输出左转优先时,从S到E的步数 ...

  8. [LeetCode]695. 岛屿的最大面积(DFS/BFS)、200. 岛屿数量(DFS/BFS待做/并差集待做)

    695. 岛屿的最大面积 题目 给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合.你可以假设二维矩阵的四个边缘都被 ...

  9. POJ2308连连看dfs+bfs+优化

    DFS+BFS+MAP+剪枝 题意:       就是给你一个10*10的连连看状态,然后问你最后能不能全部消没? 思路:      首先要明确这是一个搜索题目,还有就是关键的一点就是连连看这个游戏是 ...

随机推荐

  1. BZOJ3355

    3355: [Usaco2004 Jan]有序奶牛 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 37  Solved: 19[Submit][Sta ...

  2. [NOIP 2018 Day1] 简要题解

    [题目链接] 铺设道路 : https://www.luogu.org/problemnew/show/P5019 货币系统 : https://www.luogu.org/problemnew/sh ...

  3. 传统开发有必要学Dubbo吗

    dubbo作为一个知名的分布式服务调用框架,在众多互联网公司都有广泛的应用.但其本质还是一个远程服务调用框架,最初就是为了应对SOA服务治理时才用到的,如果本身服务不多就没必要用它了.如果对技术感兴趣 ...

  4. webpack 工作方式

    把你的项目当做一个整体,通过一个给定的主文件(如index.js),webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个或多个 浏览器可识别额javas ...

  5. codeforces 126B

    Asterix, Obelix and their temporary buddies Suffix and Prefix has finally found the Harmony temple. ...

  6. mysql连接过多-报错

    有两种方法: 1,错误连接参数 max_connect_errors,在配置文件中调整增大. 比如:修改mysql配置文件,在[mysqld]字段下面添加 max_connect_errors=102 ...

  7. rn滑动返回页面监听

    开发rn的同学都已经知道这个问题很坑了,真的很难弄,网上的方法尝试过很多,返回的的时候回调,是用的最多的,最开始我也是用的这种方式,但是滑动返回的时候监听不到.并且用起来也比较麻烦,不但需要在当前页面 ...

  8. poj1312dfs基础

    就是很简单的DFS-因为数据偏小,上去就是干了 #include <stdio.h> #include <string.h> #include <math.h> # ...

  9. bzoj 1385: [Baltic2000]Division expression【脑洞】

    加括号再去括号就是除变加,显然尽可能多的除变加是最优的,然后发现唯一不能变成乘数的是第二个数,所以把其他数乘起来mod第二个数,如果是0就是YES,否则说明最后不能除尽,就是NO #include&l ...

  10. 黑客攻防技术宝典web实战篇:攻击应用程序逻辑习题

    猫宁!!! 参考链接:http://www.ituring.com.cn/book/885 随书答案. 1. 何为强制浏览?可以通过它确定哪些漏洞? 强制浏览包括避开浏览器导航对应用程序功能访问顺序实 ...