注:以下讲解均以迷宫来形象的表述
1.深度优先算法(DFS)
1.1 概念
是一种枚举所有完整路径以遍历所有情况的搜索方法。以迷宫为例,就是当碰到岔道口时,总是以“深度”为前进的关键字,不碰到死胡同就不回头。
1.2 实现
一般以递归方法实现,当然也可以用非递归的方法,不过需要使用栈,与递归算法本质相同。使用DFS解决问题要注意剪枝。
对于“剪枝”不理解可以看:树相关结论
1.3 应用
主要应用于图和树的遍历算法中。另外,还要一类问题可以用DFS算法:
给定一个序列,枚举这个序列所有子序列(可以不连续)。进而可以从中选择一个符合要求的“最优”子序列。
例题:1103 Integer Factorization
2.广度优先搜索(BFS)
2.1 概念
以广度为第一关键词,当碰到岔道口时,总是先依次访问从该岔道口能直接到达的所有结点,然后再按这些结点被访问的顺序去依次访问它们能直接到达的所有结点,以此类推,直到访问完所有结点。如下示意图,就像往平静水面投入一颗小石子激起的水波一样。
2.2 实现
一般用队列实现BFS,每次将下一层的结点入队。
bool inq[];
void BFS(int s){
queue<int> q;
q.push(s);
while(!q.empty()){
取出队首元素top;
访问队首元素top;
将队首元素出队;
将top的下一层结点中未曾入队(inq==false)的结点全部入队,并设置为已入队(inq=true)
}
}
2.3 应用
主要应用于树的层序遍历及图的遍历。另外,还有一类重要问题可以用BFS解决:
@求“块”的个数(二维或三维)
- 二维
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 100;
int m, n, matrix[maxn][maxn];
bool inq[maxn][maxn];
int X[4] = { 0,0,1,-1 }, Y[4] = { 1,-1,0,0 }; //增量数组
struct node {
int x, y; //坐标位置
};
bool judge(int x, int y) {
if (x >= n || x < 0 || y >= m || y < 0) return false; //出了边界
if (matrix[x][y] == 0 || inq[x][y]) return false; //不是"1"或者入队过
return true;
}
void bfs(int x, int y) {
queue<node> q;
q.push({ x,y });
inq[x][y] = true;
while (!q.empty()) {
node top = q.front(); //取出队首元素
q.pop(); //出队
for (int i = 0; i < 4; i++) {
int newx = top.x + X[i];
int newy = top.y + Y[i];
if (judge(newx, newy)) {
q.push({ newx,newy });
inq[newx][newy] = true;
}
}
}
}
int main() {
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif
cin >> m >> n;
for (int x = 0; x < n; x++) { //n为矩阵行数
for (int y = 0; y < m; y++) { //m为矩阵列数
scanf("%d", &matrix[x][y]);
}
}
int ans = 0; //"块"的个数
for (int x = 0; x < n; x++) {
for (int y = 0; y < m; y++) {
if (matrix[x][y] && inq[x][y] == false) {
ans++;
bfs(x, y);
}
}
}
printf("%d\n", ans);
return 0;
}
测试用例:
7 6
0 1 1 1 0 0 1
0 0 1 0 0 0 0
0 0 0 0 1 0 0
0 0 0 1 1 1 0
1 1 1 0 1 0 0
1 1 1 1 0 0 0
- 三维——1091 Acute Stroke (30分)
如果没有BFS的思维,会觉得这是一个很魔幻的题目(可能因为我菜)。但是从二维延伸到三维,其实思路一样,只是要求的物理量不一样,对应一些小细节有改变而已。
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
struct node {
int x, y, z;
};
int matrix[1300][130][65], m, n, L, T;
bool inq[1300][130][65];
int X[6] = { 1,0,-1,0,0,0 }, Y[6] = { 0,1,0,-1,0,0 }, Z[6] = { 0,0,0,0,1,-1 };
bool judge(int x, int y, int z) {
if (x < 0 || x >= m || y < 0 || y >= n || z < 0 || z >= L) return false;
if (matrix[x][y][z] == 0 || inq[x][y][z]) return false;
return true;
}
int ans = 0;
void bfs(int x, int y, int z) {
int num=0;
queue<node> q;
q.push({ x,y,z });
inq[x][y][z] = 1;
while (!q.empty()) {
node top = q.front();
q.pop();
num++; //每次q非空就累加这个"块"的元素个数
for (int i = 0; i < 6; i++) {
int newx = top.x + X[i];
int newy = top.y + Y[i];
int newz = top.z + Z[i];
if (judge(newx, newy, newz)) {
inq[newx][newy][newz] = 1;
q.push({ newx,newy,newz });
}
}
}
if (num >= T) ans += num; //q空了,说明这个块遍历完了
}
int main() {
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif
cin >> m >> n >> L >> T;
for (int z = 0; z < L; z++) {
for (int x = 0; x < m; x++) {
for (int y = 0; y < n; y++) {
scanf("%d", &matrix[x][y][z]);
}
}
}
for (int z = 0; z < L; z++) {
for (int x = 0; x < m; x++) {
for (int y = 0; y < n; y++) {
if (matrix[x][y][z] == 1 && inq[x][y][z] == false) {
bfs(x,y,z);
}
}
}
}
cout << ans;
return 0;
}