DFS、BFS和Backtracking模板
区别与联系
区别
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模板的更多相关文章
- DFS/BFS+思维 HDOJ 5325 Crazy Bobo
题目传送门 /* 题意:给一个树,节点上有权值,问最多能找出多少个点满足在树上是连通的并且按照权值排序后相邻的点 在树上的路径权值都小于这两个点 DFS/BFS+思维:按照权值的大小,从小的到大的连有 ...
- 【DFS/BFS】NYOJ-58-最少步数(迷宫最短路径问题)
[题目链接:NYOJ-58] 经典的搜索问题,想必这题用广搜的会比较多,所以我首先使的也是广搜,但其实深搜同样也是可以的. 不考虑剪枝的话,两种方法实践消耗相同,但是深搜相比广搜内存低一点. 我想,因 ...
- ID(dfs+bfs)-hdu-4127-Flood-it!
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4127 题目意思: 给n*n的方格,每个格子有一种颜色(0~5),每次可以选择一种颜色,使得和左上角相 ...
- [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 ...
- HDU 4771 (DFS+BFS)
Problem Description Harry Potter has some precious. For example, his invisible robe, his wand and hi ...
- DFS/BFS视频讲解
视频链接:https://www.bilibili.com/video/av12019553?share_medium=android&share_source=qq&bbid=XZ7 ...
- POJ 3083 -- Children of the Candy Corn(DFS+BFS)TLE
POJ 3083 -- Children of the Candy Corn(DFS+BFS) 题意: 给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走 1)先输出左转优先时,从S到E的步数 ...
- [LeetCode]695. 岛屿的最大面积(DFS/BFS)、200. 岛屿数量(DFS/BFS待做/并差集待做)
695. 岛屿的最大面积 题目 给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合.你可以假设二维矩阵的四个边缘都被 ...
- POJ2308连连看dfs+bfs+优化
DFS+BFS+MAP+剪枝 题意: 就是给你一个10*10的连连看状态,然后问你最后能不能全部消没? 思路: 首先要明确这是一个搜索题目,还有就是关键的一点就是连连看这个游戏是 ...
随机推荐
- web项目中url-pattern改成'/'后,js、css、图片等静态资源(404)无法访问问题解决办法
感谢http://blog.csdn.net/this_super/article/details/7884383的文章 1.增加静态资源url映射 如Tomcat, Jetty, JBoss, Gl ...
- 利用高德地图javascriptAPI做一个自己的地图
最近由于项目中需要制作一个地图,用来选择活动地点,我就花了两天利用高德地图的javascriptAPI自制了一个地图的demo.在这了记录一下我学习的过程. 一.进入高德地图官网,再找到高德地图的开放 ...
- 重新安装VMware10提示"The Msi '' Failed"问题解决方案
想把虚拟机软件升级以下,没想到卸载的时候不干净,再安装的时候总提示让我先卸载旧版本但实际上旧版本已经卸载过了,这里又没法再卸载一次,所以就提示”The MSI '' failed“ 显然,安装程序还是 ...
- ORA-01843: not a valid month 错误
转自:https://blog.csdn.net/jetluning/article/details/48785599 insert into ......的场合发生ORA-01843: not a ...
- 修改CentOS系统的默认启动级别
======修改CentOS系统的默认启动级别====== 现在的Linux系统安装完后就运行在第5个级别,即系统启动后直接进入图形界面,而不用在字符模式下登录后用startx或者xinit来起动图形 ...
- 用Xtrabackup实现MySQL全库备份与恢复
xtrabackup包含两个主要的工具,即xtrabackup和innobackupex,二者区别如下: (1)xtrabackup只能备份innodb和xtradb两种引擎的表,而不能备份myisa ...
- Java基本数据类型与包装类型(转)
基本数据类型的包装类 为什么需要包装类? Java并不是纯面向对象的语言.Java语言是一个面向对象的语言,但是Java的基本数据类型却不是面向对象的.但是我们在实际使用中经常需要将基本数据转化成对象 ...
- [ssh]记ssh的几种玩法
得到一台Linux的服务器,我们可以进行以下几种玩法: 先讲一讲几个参数: -f 要求 ssh在执行命令前退至后台.它用于当ssh准备询问口令或密语,但是用户希望它在后台进行.该选项隐含了-n选 ...
- HDOJ3231醉
反正一开始就是瞎几把看题,然后题意理解了,什么飞机?只能去看题解了. 呵呵,可惜,题解看了三个小时,还是一知半解,先写了. - -菜鸡超级详细题解,强行掰弯一波,等下再问问别人吧. OK,OK开始!! ...
- python 面向对象十三 枚举类
from enum import Enum Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', ...