当青训营遇上码上掘金,让我们通过主题3 —— 寻友之旅来开启这趟旅程。
题目
主题 3:寻友之旅
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
分析
这道题很明显是通过 BFS 进行搜索,因为 N 与 K 的数据范围都不算太大,所以爆搜肯定是在时间范围内的。
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
const int NN = 100010;
int bfs(int N, int K) {
int M = max(N, K) + 11;
queue<int> q;
vector<int> d(M, NN);
vector<bool> v(M, false);
d[N] = 0;
q.push(N);
v[N] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
if (d[u] + 1 >= d[u - 1]) {
} else {
if (u <= 0) {}
else {
d[u - 1] = d[u] + 1;
if (v[u - 1]) {}
else {
q.push(u - 1);
v[u - 1] = true;
}
}
}
if (d[u + 1] > d[u] + 1)
if (u < M - 1) {
d[u + 1] = d[u] + 1;
if (v[u + 1]) {}
else {
q.push(u + 1);
v[u + 1] = true;
}
} else {}
if (d[2 * u] > d[u] + 1) {
if (2 * u > M - 1) continue;
d[2 * u] = d[u] + 1;
if (v[2 * u]) continue;
q.push(2 * u);
v[2 * u] = true;
}
}
return d[K];
}
int main() {
int N, K;
scanf("%d%d", &N, &K);
printf("%d", bfs(N, K));
}
思考
关于深度搜索与宽度搜索实际上都有一个比较简单的模板,将模板以及模版题掌握清楚之后完成这类题的难度并不会很大。
DFS
int dfs(int u)
{
st[u] = true; // st[u] 表示点u已经被遍历过
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (!st[j]) dfs(j);
}
}
BFS
queue<int> q;
st[1] = true; // 表示1号点已经被遍历过
q.push(1);
while (q.size())
{
int t = q.front();
q.pop();
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (!st[j])
{
st[j] = true; // 表示点j已经被遍历过
q.push(j);
}
}
}
总结
DFS 和 BFS 主要是运用于对于图和树的搜索,很多问题模型都是可以建模变成一个图或者树的,所以差不多不少问题都会涉及到这两个。比如求二叉树深度,可以是递归的方法,属于 DFS(深度优先搜索);另一种方法是按照层次遍历,属于 BFS(广度优先搜索)。再比如寻找一条路径,利用DFS或BFS寻找从源顶点到终点的路径。
但是不管是BFS还是DFS,它们虽然好用,由于时间和空间的局限性,以至于它们只能解决数据量小的问题。