2024/1/30 dfs与bfs

想要了解dfs与bfs,就得了解队列和栈。

一、栈与队列

1.栈

栈说白了就是先入后出。把栈类比为一个容器。只有一个口,所以如果我们想要取出最底层也就是最先放入的元素,只能最后取出它。

栈基础操作有如下几种:

  1. push 放入
  2. pop 拿出
  3. empty 是否为空
  4. size 栈的大小
  5. top 获取栈顶元素

下面将用两种方式实现:

  1. 用数组或者链表模拟栈
    #include <iostream>
    using namespace std;const int N = 100;int stk[N], top = 0;int main()
    {//使用数组模拟栈int x;cin >> x;//push放入栈中stk[++top] = x;//输出栈顶元素cout << stk[top] << endl;//pop拿出(不管top元素删不删,top--就行)top--;// 常用的就是,获取栈顶元素的同时,弹出栈顶元素int u = stk[top--];return 0;
    }

    以上是普通静态数组。但是考虑到现实生活由于入栈的元素可能会源源不断地增加,因此我们可以使用动态数组或者链表,这样就无须自行处理数组扩容问题。这里贴出hello算法里对这个的网址。https://www.hello-algo.com/chapter_stack_and_queue/stack/#1icon-default.png?t=N7T8https://www.hello-algo.com/chapter_stack_and_queue/stack/#1

  2. stl库写栈

首先就是 #include <stack>

定义:stack<数据类型> stk;

使用:

  • stk.push(x);
  • stk.pop();
  • stk.top();
  • stk.empty();//true表示空
  • stk.size();//返回正整数
#include <iostream>
#include <stack>
using namespace std;int main()
{stack<int>stk;int x;cin >> x;//放入栈中stk.push(x);//输出栈顶cout << stk.top() << endl;//弹出栈顶stk.pop();return 0;
}

2.队列

队列则是:“先入先出”。「队列 queue」是一种遵循先入先出规则的线性数据结构。顾名思义,队列模拟了排队现象,即新来的人不断加入队列尾部,而位于队列头部的人逐个离开。

队列基础操作有如下几种:

  1. push 放入(从队尾)
  2. pop 拿出(从队首)
  3. empty 是否为空
  4. size 栈的大小
  5. front
#include <iostream>
using namespace std;const int N = 100;int q[N], front = 0, tail = 0;int main()
{//使用数组模拟队列int x;cin >> x;//push 放入队列中q[++tail] = x;//pop 把元素移除(只能从队首)front++;//size 队列长度int size = tail - front + 1;//empty 看size是否为0//front return q[front];return 0;
}
/* 初始化队列 */
queue<int> queue;/* 元素入队 */
queue.push(1);
queue.push(3);
queue.push(2);
queue.push(5);
queue.push(4);/* 访问队首元素 */
int front = queue.front();/* 元素出队 */
queue.pop();/* 获取队列的长度 */
int size = queue.size();/* 判断队列是否为空 */
bool empty = queue.empty();

额外:优先队列,双向队列

http://t.csdnimg.cn/KpFjNicon-default.png?t=N7T8http://t.csdnimg.cn/KpFjN5.2   队列 - Hello 算法 (hello-algo.com)icon-default.png?t=N7T8https://www.hello-algo.com/chapter_stack_and_queue/queue/#5215.3   双向队列 - Hello 算法 (hello-algo.com)icon-default.png?t=N7T8https://www.hello-algo.com/chapter_stack_and_queue/deque/

/* 初始化双向队列 */
deque<int> deque;/* 元素入队 */
deque.push_back(2);   // 添加至队尾
deque.push_back(5);
deque.push_back(4);
deque.push_front(3);  // 添加至队首
deque.push_front(1);/* 访问元素 */
int front = deque.front(); // 队首元素
int back = deque.back();   // 队尾元素/* 元素出队 */
deque.pop_front();  // 队首元素出队
deque.pop_back();   // 队尾元素出队/* 获取双向队列的长度 */
int size = deque.size();/* 判断双向队列是否为空 */
bool empty = deque.empty();

双向队列兼具栈与队列的逻辑,因此它可以实现这两者的所有应用场景,同时提供更高的自由度

我们知道,软件的“撤销”功能通常使用栈来实现:系统将每次更改操作 push 到栈中,然后通过 pop 实现撤销。然而,考虑到系统资源的限制,软件通常会限制撤销的步数(例如仅允许保存 50 步)。当栈的长度超过 50 时,软件需要在栈底(队首)执行删除操作。但栈无法实现该功能,此时就需要使用双向队列来替代栈。请注意,“撤销”的核心逻辑仍然遵循栈的先入后出原则,只是双向队列能够更加灵活地实现一些额外逻辑。

二、DFS深度优先搜索-----栈

 1.指数型搜索

模板:

void dfs(int step){
    判断边界
    尝试每一种可能 for(i=1;i<=n;i++){
        继续下一步 dfs(step+1)
        }
    返回
}

#include <iostream>using namespace std;const int N = 100;int n;//输入的节点数  
int st[N] = {}; //决策数组 0 表示没有搜索过, 1表示选择 , 2表示没有选择// 对于每一个点,都需要有一次决策,无论是1还是2 
// 搜索是把所有的情况都考虑 // u表示对u进行抉择,已经抉择了u个数
void dfs(int u) {// 递归出口,当所有节点都决策完毕时输出结果  if (u > n){for (int i = 0; i < n; i++) {// 只有当第i个节点被选择时才输出 if (st[u] = 1){cout << i << " ";}}}// 选择第u个节点(标记为1)并继续搜索下一个节点st[u] = 1;dfs(u + 1);// 恢复第u个节点的状态(标记为0)并选择不选择第u个节点(标记为2)并继续搜索下一个节点st[u] = 0;st[u] = 2;dfs(u + 1);// 继续恢复第u个节点的状态(标记为0)以备下次决策使用  st[u] = 0;
}
int main()
{cin >> n;dfs(1);return 0;
}


Python Tutor code visualizer: Visualize code in Python, JavaScript, C, C++, and Javaicon-default.png?t=N7T8https://pythontutor.com/render.html#code=%23include%20%3Ciostream%3E%0A%0Ausing%20namespace%20std%3B%0A%0Aconst%20int%20N%20%3D%20100%3B%0A%0Aint%20n%20,%20st%5BN%5D%20%3D%20%7B%7D%3B%20//%200%20%E8%A1%A8%E7%A4%BA%E6%B2%A1%E6%9C%89%E6%90%9C%E7%B4%A2%E8%BF%87%EF%BC%8C%201%E8%A1%A8%E7%A4%BA%E9%80%89%E6%8B%A9%20%EF%BC%8C%202%E8%A1%A8%E7%A4%BA%E6%B2%A1%E6%9C%89%E9%80%89%E6%8B%A9%0A%0A//%20%E5%AF%B9%E4%BA%8E%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%82%B9%EF%BC%8C%E9%83%BD%E9%9C%80%E8%A6%81%E6%9C%89%E4%B8%80%E6%AC%A1%E5%86%B3%E7%AD%96%EF%BC%8C%E6%97%A0%E8%AE%BA%E6%98%AF1%E8%BF%98%E6%98%AF2%20%0A//%20%E6%90%9C%E7%B4%A2%E6%98%AF%E6%8A%8A%E6%89%80%E6%9C%89%E7%9A%84%E6%83%85%E5%86%B5%E9%83%BD%E8%80%83%E8%99%91%20%0A%0A//%20u%E8%A1%A8%E7%A4%BA%E5%AF%B9u%E8%BF%9B%E8%A1%8C%E6%8A%89%E6%8B%A9%EF%BC%8C%E5%B7%B2%E7%BB%8F%E6%8A%89%E6%8B%A9%E4%BA%86u%E4%B8%AA%E6%95%B0%20%0Avoid%20dfs%28%20int%20u%20%29%20%7B%0A%20%20%20%20%0A%20%20%20%20//%20%E9%80%92%E5%BD%92%E5%87%BA%E5%8F%A3%20%EF%BC%8C%20%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%82%B9%E9%83%BD%E6%8A%89%E6%8B%A9%E8%BF%87%E4%BA%86%20%0A%20%20%20%20if%28u%20%3E%20n%20%29%7B%0A%20%20%20%20%20%20%20%20for%28int%20i%20%3D%201%3B%20i%20%3C%3D%20n%20%3B%20i%2B%2B%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20%E6%88%91%E4%BB%AC%E5%8F%AA%E6%9C%89%E5%9C%A8%E9%80%89%E6%8B%A9%E7%AC%ACi%E4%B8%AA%E7%82%B9%E7%9A%84%E6%97%B6%E5%80%99%E8%BE%93%E5%87%BA%20%0A%20%20%20%20%20%20%20%20%20%20%20%20if%28st%5Bu%5D%20%3D%3D%201%20%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cout%20%3C%3C%20i%20%3C%3C%20%22%20%22%20%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%3B%0A%20%20%20%20%7D%0A%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20//%20%E9%80%89%E6%8B%A9%0A%20%20%20%20//%20st%5Bu%5D%20%3D%200%3B%20%E8%BF%99%E5%8F%A5%E8%AF%9D%E9%80%9A%E5%B8%B8%E7%9C%81%E7%95%A5%20%0A%20%20%20%20st%5Bu%5D%20%3D%201%3B%0A%20%20%20%20dfs%28u%20%2B%201%29%3B%0A%20%20%20%20%0A%20%20%20%20//%20%E6%81%A2%E5%A4%8D%E7%8E%B0%E5%9C%BA%EF%BC%8C%E6%8E%A7%E5%88%B6%E5%8F%98%E9%87%8F%20%EF%BC%9A%20%E5%8D%95%E4%B8%80%E5%8F%98%E9%87%8F%E5%8E%9F%E5%88%99%20%0A%20%20%20%20st%5Bu%5D%20%3D%200%3B%20%0A%20%20%20%20//%20%E4%B8%8D%E9%80%89%E6%8B%A9%20%0A%20%20%20%20st%5Bu%5D%20%3D%202%3B%0A%20%20%20%20dfs%28u%20%2B%201%29%3B%0A%20%20%20%20%0A%20%20%20%20//%20%E7%BB%A7%E7%BB%AD%E6%81%A2%E5%A4%8D%E7%8E%B0%E5%9C%BA%0A%20%20%20%20st%5Bu%5D%20%3D%200%3B%20%0A%7D%0A%0Aint%20main%28%29%7B%0A%20%20n%3D3%3B%0A%20%20%20%20dfs%281%29%3B%0A%20%20%20%20%0A%20%20%20%20return%200%3B%0A%7D&cppShowMemAddrs=true&cumulative=false&curInstr=38&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=cpp_g%2B%2B9.3.0&rawInputLstJSON=%5B%5D&textReferences=false

例题1 P2036 Perket

 

#include <iostream>  
#include <algorithm>  
#include <cstdio>  
#include <cmath>  
using namespace std;  // 全局变量声明  
int n; // n代表数字的个数  
int mindif = 999999999; // mindif用于存储最小差值,初始化为一个非常大的数  
int s[10], b[10]; // s数组和b数组分别用于存储输入的数字和它们对应的值  // perket函数是一个递归函数,用于计算所有可能的组合  
// u代表当前处理的数字的索引  
// sp代表当前选择的s数组中数字的乘积  
// bs代表当前选择的b数组中数字的和  
void perket(int u, int sp, int bs) {  // 递归终止条件:当u大于n时,表示所有数字都已经处理完毕  if (u > n) {  // 如果bs为0,表示没有选择任何b数组中的数字,直接返回  if (!bs) {  return;  }  // 更新最小差值  mindif = min(mindif, abs(sp - bs));  return;  }  // 递归调用1:不选择当前数字  perket(u + 1, sp, bs);  // 递归调用2:选择当前数字  perket(u + 1, sp * s[u], bs + b[u]);  
}  int main() {  // 输入数字的个数  cin >> n;  // 输入每个数字及其对应的值  for (int i = 1; i <= n; i++) {  cin >> s[i] >> b[i];  }  // 调用perket函数开始计算  perket(1, 1, 0);  // 输出最小差值  cout << mindif << endl;  return 0;  
}

Python Tutor code visualizer: Visualize code in Python, JavaScript, C, C++, and Javaicon-default.png?t=N7T8https://pythontutor.com/render.html#code=%23include%20%3Ciostream%3E%20%20%0A%23include%20%3Calgorithm%3E%20%20%0A%23include%20%3Ccstdio%3E%20%20%0A%23include%20%3Ccmath%3E%20%20%0Ausing%20namespace%20std%3B%20%20%0A%20%20%0A//%20%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E5%A3%B0%E6%98%8E%20%20%0Aint%20n%3B%20//%20n%E4%BB%A3%E8%A1%A8%E6%95%B0%E5%AD%97%E7%9A%84%E4%B8%AA%E6%95%B0%20%20%0Aint%20mindif%20%3D%20999999999%3B%20//%20mindif%E7%94%A8%E4%BA%8E%E5%AD%98%E5%82%A8%E6%9C%80%E5%B0%8F%E5%B7%AE%E5%80%BC%EF%BC%8C%E5%88%9D%E5%A7%8B%E5%8C%96%E4%B8%BA%E4%B8%80%E4%B8%AA%E9%9D%9E%E5%B8%B8%E5%A4%A7%E7%9A%84%E6%95%B0%20%20%0Aint%20s%5B10%5D,%20b%5B10%5D%3B%20//%20s%E6%95%B0%E7%BB%84%E5%92%8Cb%E6%95%B0%E7%BB%84%E5%88%86%E5%88%AB%E7%94%A8%E4%BA%8E%E5%AD%98%E5%82%A8%E8%BE%93%E5%85%A5%E7%9A%84%E6%95%B0%E5%AD%97%E5%92%8C%E5%AE%83%E4%BB%AC%E5%AF%B9%E5%BA%94%E7%9A%84%E5%80%BC%20%20%0A%20%20%0A//%20perket%E5%87%BD%E6%95%B0%E6%98%AF%E4%B8%80%E4%B8%AA%E9%80%92%E5%BD%92%E5%87%BD%E6%95%B0%EF%BC%8C%E7%94%A8%E4%BA%8E%E8%AE%A1%E7%AE%97%E6%89%80%E6%9C%89%E5%8F%AF%E8%83%BD%E7%9A%84%E7%BB%84%E5%90%88%20%20%0A//%20u%E4%BB%A3%E8%A1%A8%E5%BD%93%E5%89%8D%E5%A4%84%E7%90%86%E7%9A%84%E6%95%B0%E5%AD%97%E7%9A%84%E7%B4%A2%E5%BC%95%20%20%0A//%20sp%E4%BB%A3%E8%A1%A8%E5%BD%93%E5%89%8D%E9%80%89%E6%8B%A9%E7%9A%84s%E6%95%B0%E7%BB%84%E4%B8%AD%E6%95%B0%E5%AD%97%E7%9A%84%E4%B9%98%E7%A7%AF%20%20%0A//%20bs%E4%BB%A3%E8%A1%A8%E5%BD%93%E5%89%8D%E9%80%89%E6%8B%A9%E7%9A%84b%E6%95%B0%E7%BB%84%E4%B8%AD%E6%95%B0%E5%AD%97%E7%9A%84%E5%92%8C%20%20%0Avoid%20perket%28int%20u,%20int%20sp,%20int%20bs%29%20%7B%20%20%0A%20%20%20%20//%20%E9%80%92%E5%BD%92%E7%BB%88%E6%AD%A2%E6%9D%A1%E4%BB%B6%EF%BC%9A%E5%BD%93u%E5%A4%A7%E4%BA%8En%E6%97%B6%EF%BC%8C%E8%A1%A8%E7%A4%BA%E6%89%80%E6%9C%89%E6%95%B0%E5%AD%97%E9%83%BD%E5%B7%B2%E7%BB%8F%E5%A4%84%E7%90%86%E5%AE%8C%E6%AF%95%20%20%0A%20%20%20%20if%20%28u%20%3E%20n%29%20%7B%20%20%0A%20%20%20%20%20%20%20%20//%20%E5%A6%82%E6%9E%9Cbs%E4%B8%BA0%EF%BC%8C%E8%A1%A8%E7%A4%BA%E6%B2%A1%E6%9C%89%E9%80%89%E6%8B%A9%E4%BB%BB%E4%BD%95b%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E6%95%B0%E5%AD%97%EF%BC%8C%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%20%20%0A%20%20%20%20%20%20%20%20if%20%28!bs%29%20%7B%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20return%3B%20%20%0A%20%20%20%20%20%20%20%20%7D%20%20%0A%20%20%20%20%20%20%20%20//%20%E6%9B%B4%E6%96%B0%E6%9C%80%E5%B0%8F%E5%B7%AE%E5%80%BC%20%20%0A%20%20%20%20%20%20%20%20mindif%20%3D%20min%28mindif,%20abs%28sp%20-%20bs%29%29%3B%20%20%0A%20%20%20%20%20%20%20%20return%3B%20%20%0A%20%20%20%20%7D%20%20%0A%20%20%20%20%20%20%0A%20%20%20%20//%20%E9%80%92%E5%BD%92%E8%B0%83%E7%94%A81%EF%BC%9A%E4%B8%8D%E9%80%89%E6%8B%A9%E5%BD%93%E5%89%8D%E6%95%B0%E5%AD%97%20%20%0A%20%20%20%20perket%28u%20%2B%201,%20sp,%20bs%29%3B%20%20%0A%20%20%20%20%20%20%0A%20%20%20%20//%20%E9%80%92%E5%BD%92%E8%B0%83%E7%94%A82%EF%BC%9A%E9%80%89%E6%8B%A9%E5%BD%93%E5%89%8D%E6%95%B0%E5%AD%97%20%20%0A%20%20%20%20perket%28u%20%2B%201,%20sp%20*%20s%5Bu%5D,%20bs%20%2B%20b%5Bu%5D%29%3B%20%20%0A%7D%20%20%0A%20%20%0Aint%20main%28%29%20%7B%20%20%0A%20%20%20%20//%20%E8%BE%93%E5%85%A5%E6%95%B0%E5%AD%97%E7%9A%84%E4%B8%AA%E6%95%B0%20%20%0A%20%20%20%20n%3D4%3B%0A%20%20%20%20%20%20%0A%20%20%20%20//%20%E8%BE%93%E5%85%A5%E6%AF%8F%E4%B8%AA%E6%95%B0%E5%AD%97%E5%8F%8A%E5%85%B6%E5%AF%B9%E5%BA%94%E7%9A%84%E5%80%BC%20%20%0A%20%20%20%20s%5B0%5D%3D1,s%5B1%5D%3D2,s%5B2%5D%3D3,s%5B3%5D%3D4%3B%0A%20%20%20%20b%5B0%5D%3D7,b%5B1%5D%3D6,b%5B2%5D%3D8,b%5B3%5D%3D9%3B%0A%20%20%20%20%20%20%0A%20%20%20%20//%20%E8%B0%83%E7%94%A8perket%E5%87%BD%E6%95%B0%E5%BC%80%E5%A7%8B%E8%AE%A1%E7%AE%97%20%20%0A%20%20%20%20perket%281,%201,%200%29%3B%20%20%0A%20%20%20%20%20%20%0A%20%20%20%20//%20%E8%BE%93%E5%87%BA%E6%9C%80%E5%B0%8F%E5%B7%AE%E5%80%BC%20%20%0A%20%20%20%20cout%20%3C%3C%20mindif%20%3C%3C%20endl%3B%20%20%0A%20%20%20%20%20%20%0A%20%20%20%20return%200%3B%20%20%0A%7D&cppShowMemAddrs=true&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=cpp_g%2B%2B9.3.0&rawInputLstJSON=%5B%5D&textReferences=false

在给定的代码中,每次递归的两种选择(选择当前数字和不选择当前数字)可能会产生重复的结果。这意味着,递归函数perket可能会计算出重复的组合。

为了解决这个问题,可以在递归过程中添加一些逻辑来跳过已经计算过的组合,或者使用其他方法来避免重复计算。例如,可以维护一个集合或哈希集合来跟踪已经计算过的组合,并在递归函数中进行检查。

如果不采取措施避免重复计算,则可能会导致递归函数的时间复杂度增加,因为重复计算相同的组合会导致更多的递归调用。在处理大量数据时,这可能会导致性能问题。

2.组合型搜索

例题2 全排列

【题意】
先给一个正整数 ( 1 < = n < = 10 ),输出所有全排列。
什么是全排列,例如n=3,输出所有组合,并且按字典序输出:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
每个全排列一行,相邻两个数用空格隔开(最后一个数后面没有空格)
【输入格式】
一行一个整数n。
【输出格式】
输出1~n的所有全排列。
【样例输入】
3
【样例输出】
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

#include <iostream>  // 引入输入输出流库  
#include <algorithm>  // 引入算法库  
#include <cstdio>      // 引入标准输入输出库  
#include <cmath>        // 引入数学库  
using namespace std;     // 使用标准命名空间  int n, ans[10], used[10];   // 定义全局变量,n表示要选取的数字个数,ans数组用于存放结果,used数组用于标记数字是否被使用过  void dfs(int cnt){          // 定义深度优先搜索函数,cnt表示当前已经选取的数字个数  if (cnt > n) {           // 如果已经选取的数字个数大于n,说明已经选取了所有数字,输出结果并返回  for (int i = 1; i <= n; i++) { // 遍历所有数字并输出  cout << ans[i] << " ";  }  cout << endl;  return;  }  for (int i = 1; i <= n; i++){ // 枚举所有数字  if (used[i] == 0) {      // 如果数字i还没有被使用过  ans[cnt] = i;        // 将数字i放入当前位置  used[i] = 1;          // 标记数字i为已使用  dfs(cnt + 1);        // 递归搜索下一个位置  ans[cnt] = 0;         // 撤销当前位置的选择,即清空当前位置  used[i] = 0;           // 撤销对数字i的选择,即将其标记为未使用  }  }  
}  int main() {                  // 主函数  cin >> n;                  // 输入要选取的数字个数n  dfs(1);                     // 从第一个位置开始搜索  return 0;                   // 程序正常结束  
}

这段代码中的回溯是通过以下步骤实现的:

1. 在dfs函数中,首先检查是否已经选取了所有数字(即`cnt`是否大于`n`)。如果是,则输出当前结果并返回。
2. 然后,函数使用一个循环来枚举所有数字。如果某个数字还没有被使用过(即`used[i]`等于0),则进行以下操作:

  •     将该数字放入当前位置(即`ans[cnt] = i`)。
  •     标记该数字为已使用(即`used[i] = 1`)。
  •     递归调用`dfs(cnt + 1)`来搜索下一个位置。

3. 在递归调用返回后,执行回溯操作:

  •     撤销当前位置的选择,即将`ans[cnt]`重置为0,表示该位置还没有被选择。
  •     撤销对数字`i`的选择,即将`used[i]`重置为0,表示数字`i`现在可以再次被选择。

4. 重复上述过程,直到所有可能的排列都被探索完为止。

通过这种方式,代码能够撤销之前的决策,尝试其他可能的路径,从而全面地探索所有可能的解空间。

还有几个题,以后补补(太赶了qaq

三、BFS广度优先搜索-----队列

bfs个人感觉就是,同时往每个方向都试试,最先得到的就是最好的。

它是一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。宽度优先搜索是一种对图进行搜索的算法。假设我们一开始位于某个顶点(即起点),此 时并不知道图的整体结构,而我们的目的是从起点开始顺着边搜索,直到到达指定顶点(即终 点)。在此过程中每走到一个顶点,就会判断一次它是否为终点。广度优先搜索会优先从离起点 近的顶点开始搜索。

b站有个视频非常清晰,这里贴下链接

【广度优先搜索BFS遍历-动画演示过程,希望对大家有所帮助~】

https://www.bilibili.com/video/BV1bP4y1K7Tr?vd_source=7ccfb0770f378b7710213a50fbacfc17icon-default.png?t=N7T8https://www.bilibili.com/video/BV1bP4y1K7Tr?vd_source=7ccfb0770f378b7710213a50fbacfc17

这个大佬写的也很清晰:

http://t.csdnimg.cn/sw4pZicon-default.png?t=N7T8http://t.csdnimg.cn/sw4pZ

int BFS(Node start, Node target) {
    入队(初始状态);
    visited[初始状态] = true;
    while(!空队) {
        for() { // 状态转换
            Node node = 队首元素;
 
            对node的处理,生成新node状态;
 
            if (visited[node] == true)
                continue;
            if (node == target) {
                输出答案;
                return 0;
            }
            v[node] = true;
            入队(node);
        }
    出队();
    }
    
}

 例题3 P1135 奇怪的电梯

#include <iostream>  // 引入输入输出流    
#include <cstring>  // 引入C风格的字符串处理函数库,用于memset  
#include <queue>  // 引入队列容器  
using namespace std;  const int N = 201;  // 定义常量N为201,表示图的最大节点数  int n, a, b;  // n为图的节点数,a为起点,b为终点  
int k[N], vis[N], ans[N];  // k数组存储每个节点的关联值,vis数组标记节点是否被访问过,ans数组存储从起点到每个节点的最短路径长度  // BFS函数,从节点a开始搜索  
void bfs(int a) {  queue<int> Q;  // 定义一个队列Q  Q.push(a);  // 将起点a加入队列  ans[a] = 0;  // 设置起点a到自身的距离为0  // 当队列不为空时继续循环  while (!Q.empty()) {  int u = Q.front();  // 取出队首元素  Q.pop();  // 弹出队首元素  // 如果当前节点是目标节点b,则结束搜索  if (u == b) {  break;  }  // 如果当前节点已经被访问过,则跳过  if (vis[u] == 1) {  continue;  }  vis[u] = 1;  // 标记当前节点为已访问  // 计算通过当前节点的关联值k[u]可以到达的两个节点v1和v2  int v1 = u + k[u];  // 如果v1是一个有效的节点且未被访问过,则将其加入队列,并更新ans[v1]  if (v1 >= 1 && v1 <= n && vis[v1] == 0) {  Q.push(v1);  ans[v1] = min(ans[v1], ans[u] + 1);  }  int v2 = u - k[u];  // 如果v2是一个有效的节点且未被访问过,则将其加入队列,并更新ans[v2]  if (v2 >= 1 && v2 <= n && vis[v2] == 0) {  Q.push(v2);  ans[v2] = min(ans[v2], ans[u] + 1);  }  }  
}  int main() {  cin >> n >> a >> b;  // 输入节点数n,起点a和终点b  // 初始化ans数组为一个很大的数(表示无穷大)  memset(ans, 0x3f, sizeof(ans));  // 输入每个节点的关联值k[i]  for (int i = 1; i <= n; i++) {  cin >> k[i];  }  bfs(a);  // 从起点a开始BFS搜索  // 如果从a到b没有路径,则输出-1,否则输出最短路径长度  if (ans[b] == 1e9) {  cout << -1 << endl;  } else {  cout << ans[b] << endl;  }  return 0;  
}

四、BFS与DFS区别

bfs 遍历节点是先进先出,dfs遍历节点是先进后出;
bfs是按层次访问的,dfs 是按照一个路径一直访问到底,当前节点没有未访问的邻居节点时,然后回溯到上一个节点,不断的尝试,直到访问到目标节点或所有节点都已访问。
bfs 适用于求源点与目标节点距离最近的情况,例如:求最短路径。dfs 更适合于求解一个任意符合方案中的一个或者遍历所有情况,例如:全排列、拓扑排序、求到达某一点的任意一条路径。
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/aliyonghang/article/details/128724989

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/450982.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全挑战:威胁建模的应对策略与实践

在数字威胁不断演变的时代&#xff0c;了解和降低网络安全风险对各种规模的组织都至关重要。威胁建模作为安全领域的一个关键流程&#xff0c;提供了一种识别、评估和应对潜在安全威胁的结构化方法。本文将深入探讨威胁建模的复杂性&#xff0c;探索其机制、方法、实际应用、优…

leetcode 1.两数之和(C++)DAY1(待补充哈希表法)

文章目录 1.题目描述示例提示 2.解答思路3.实现代码结果4.总结 1.题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&…

Quppy 注册教程,轻松通过欧洲银行同名转账绑定个人IBAN账号

Quppy 注册教程,轻松通过欧洲银行同名转账绑定个人IBAN账号 官网下载APP或者去香港区下载APP使用 https://quppy.com/ch/ 按照官方APP里的邮箱注册&#xff0c;填写邀请代码258258 能提升审核成功率&#xff0c;后添加电话和个人信息&#xff1b;需要说明的是&#xff1a;网站…

力扣 第 123 场双周赛 解题报告 | 珂学家 | 二维偏序+单调队列优化

前言 执手看歌敲金钗&#xff0c;笑语落珠明眸睐。 忽然蝴蝶春风满&#xff0c;焉教冷镜瘦朱颜。 整体评价 T3是基于map的前缀和的变形题&#xff0c;T4是二维偏序的一道应用题。 题外话&#xff0c;力扣还是实现N久之前的承诺了&#xff0c;命名权奖励&#xff0c;赞一个。 …

VC++中使用OpenCV绘制直线、矩形、圆和文字

VC中使用OpenCV绘制直线、矩形、圆和文字 在VC中使用OpenCV绘制直线、矩形、圆和文字非常简单&#xff0c;分别使用OpenCV中的line、rectangle、circle、putText这四个函数即可。具体可以参考OpenCV官方文档&#xff1a;https://docs.opencv.org/4.x/index.html 下面的代码展…

通过手写简易版RPC理解RPC原理

RPC是什么 所谓的RPC其实是为了不同主机的两个进程间通信而产生的&#xff0c;通常不同的主机之间的进程通信&#xff0c;程序编写需要考虑到网络通信的功能&#xff0c;这样程序的编写将会变得复杂。RPC就来解决这一问题的&#xff0c;一台主机上的进程对另外一台主机的进程发…

jupyter notebook更改工作目录的2个细节

详细步骤参考知乎原文&#xff1a; 如何更改Jupyter Notebook的默认工作路径&#xff1f; - 知乎 (zhihu.com​​​​​​) 步骤4中需要删除 #符号和后面的空格&#xff01;一定要删除空格&#xff0c;否则会出现语法错误的报错 步骤5中&#xff0c;经过评论区提醒后&#xf…

三维重建方法3D gaussian splatting与NeRF的区别和异同

最近学习了一些三维重建相关的内容&#xff0c;目前比较主要的重建流派就是3DGS以及NeRF&#xff0c;NeRF作为2020年发布的文章轰动一时&#xff0c;影响深远&#xff0c;有很多NeRF based的相关工作在这些年涌现。3DGS作为2023年的new talk of the town&#xff0c;其在保证合…

HBase 数据导入导出

HBase 数据导入导出 1. 使用 Docker 部署 HBase2. HBase 命令查找3. 命令行操作 HBase3.1 HBase shell 命令3.2 查看命名空间3.3 查看命名空间下的表3.4 新建命名空间3.5 查看具体表结构3.6 创建表 4. HBase 数据导出、导入4.1 导出 HBase 中的某个表数据4.2 导入 HBase 中的某…

深度学习手写字符识别:训练模型

说明 本篇博客主要是跟着B站中国计量大学杨老师的视频实战深度学习手写字符识别。 第一个深度学习实例手写字符识别 深度学习环境配置 可以参考下篇博客&#xff0c;网上也有很多教程&#xff0c;很容易搭建好深度学习的环境。 Windows11搭建GPU版本PyTorch环境详细过程 数…

代码随想录算法训练营DAY11 | 栈与队列 (2)

一、LeetCode 20 有效的括号 题目链接&#xff1a;20.有效的括号https://leetcode.cn/problems/valid-parentheses/ 思路&#xff1a;遇到左括号直接进栈&#xff1b;遇到右括号判断站顶是否有匹配的括号&#xff0c;没有就返回flase&#xff0c;有就将栈顶元素出栈&#xff1…

ctfshow——文件包含

文章目录 web 78——php伪协议第一种方法——php://input第二种方法——data://text/plain第三种方法——远程包含&#xff08;http://协议&#xff09; web 78——str_replace过滤字符php第一种方法——远程包含&#xff08;http://协议&#xff09;第二种方法——data://&…