bfs与dfs详解(经典例题 + 模板c-代码)

文章首发于:My Blog 欢迎大佬们前来逛逛

文章目录

    • 模板+解析
      • dfs
      • bfs
    • 1562. 微博转发
    • 3502. 不同路径数
    • 165. 小猫爬山

模板+解析

DFS(深度优先搜索)和BFS(广度优先搜索)是图论中两个重要的算法。

dfs

其中DFS是一种用于遍历或搜索树或图的算法,BFS则是一种用于搜索或遍历树或图的算法。两种算法都有其自身的优点和缺点,应用于不同的场景中。 DFS(深度优先搜索) 深度优先搜索是一种用于遍历搜索树或图的算法,其基本思路是从起始节点开始,沿着一条路径一直走到底,直到无法再走下去为止,然后回溯到上一个节点,继续走到另外一个路径,重复上述过程,直到遍历完所有节点。

DFS的实现方式可以采用递归或者来实现。下面是一个采用递归方式实现的DFS代码示例(C++):

void dfs(int cur, vector<int>& visited, vector<vector<int>>& graph) {
    visited[cur] = 1; // 标记当前节点已经被访问
    // 处理当前节点cur
    for (int i = 0; i < graph[cur].size(); i++) {
        int next = graph[cur][i];
        if (!visited[next]) { // 如果下一个节点未被访问
            dfs(next, visited, graph); // 继续访问下一个节点
        }
    }
}
void dfsTraversal(vector<vector<int>>& graph) {
    int n = graph.size();
    vector<int> visited(n, 0); // 初始化访问数组
    for (int i = 0; i < n; i++) {
        if (!visited[i]) { // 如果当前节点未被访问
            dfs(i, visited, graph); // 从当前节点开始进行深度优先遍历
        }
    }
}

bfs

BFS(广度优先搜索) 广度优先搜索是一种用于搜索或遍历树或图的算法,其基本思路是从起始节点开始,依次遍历当前节点的所有邻居节点,然后再依次遍历邻居节点的所有邻居节点,直到遍历到目标节点或者遍历完所有节点。 BFS的实现方式可以采用队列来实现。下面是一个采用队列方式实现的BFS代码示例(C++):

void bfsTraversal(vector<vector<int>>& graph) {
    int n = graph.size();
    vector<int> visited(n, 0); // 初始化访问数组
    queue<int> q;
    for (int i = 0; i < n; i++) {
        if (!visited[i]) { // 如果当前节点未被访问
            q.push(i); // 将当前节点加入队列
            visited[i] = 1; // 标记当前节点已经被访问
            while (!q.empty()) { // 循环遍历队列中的节点
                int cur = q.front();
                q.pop();
                // 处理当前节点cur
                for (int j = 0; j < graph[cur].size(); j++) {
                    int next = graph[cur][j];
                    if (!visited[next]) { // 如果下一个节点未被访问
                        q.push(next); // 将下一个节点加入队列
                        visited[next] = 1; // 标记下一个节点已经被访问
                    }
                }
            }
        }
    }
}

总结 DFS和BFS都是图论中常用的搜索算法,其应用广泛,例如在寻路、迷宫问题、拓扑排序、连通性等问题中都有应用。两种算法的实现方式不同,DFS采用递归或者栈实现,而BFS采用队列实现。在应用场景中,需要根据实际情况选择合适的算法来解决问题。


1562. 微博转发

1562. 微博转发

题目要求:有n个人,每个人都有关注的人和粉丝,如果某一个人发了一条微博,则他的粉丝们都会进行转发,而他的粉丝又会被他的粉丝的粉丝转发,求出在 L层关注者的前提下,微博转发数量的最大值。


我们可以观察到每个明星都有粉丝,则这些粉丝就是他们的孩子们,我们把这个明星看作是树的根节点,因此题目要求就是让我们求 从根节点出发在k层以内的不同的孩子节点的个数

注意到题目输入的是 **某一个人关注了这个明星。**是一个从孩子节点到根节点的路径

我们可以把这个路径反过来,写成:谁的粉丝有谁

这样我们就可以转换成一个树结构,从根节点出发在k层内的孩子的个数。

转换的关系如下所示,表示 x节点的孩子是 n1,n2…

然后利用bfs求得在k层内的最大的数量,其中对于k层的约束我们可以使用一个步数来进行表示,如果步数超过了k步,则直接退出;否则记录孩子的数量,同时进入孩子节点,重新开始bfs。

最后经过了bfs后,我们得到的一定k层以内最全的孩子的数量

我们可以使用邻接矩阵表示他们的关系,可以使用vector容器,也可以自己实现一个链式前向星存图,不过:

vector容器耗时: 1339 ms

链式前向星:388 ms

Ac代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N=1010;
typedef pair<int,int> PI;
vector<int> vec[N];
int n,k;
set<int> st;
bool vis[N];
/* 链式前向星
struct Edge{
    int to,next;
}edge[N];
int head[N],cnt;
bool vis[N];
void add_edge(int u,int v){
    edge[++cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt;
}
*/
int bfs(int s){
    st.clear();
    queue<PI> q;
    q.push({0,s});
    vis[s]=true;
    bool fg=false;
    while (!q.empty()){
        auto p=q.front();
        q.pop();
        int u=p.second;//当前点
        for (auto& x:vec[u]){//x表示当前点的所有孩子
            if (!vis[x]){
                if (p.first+1>k){//超过了k层
                    fg=true;
                    break;
                }
                vis[x]=true;
                st.insert(x);
                q.push({p.first+1,x});
            }
        }
        if (fg) break;
    }
    return st.size();
}
int main(){
    cin>>n>>k;
    for (int i=1;i<=n;i++){
        int x;
        cin>>x;
        while( x--){
            //num的粉丝是i
            int num;
            cin>>num;
            vec[num].push_back(i);
        }
    }
    cin>>n;
    while (n--){
        memset(vis,0,sizeof(vis));
        int num;
        cin>>num;
        cout<<bfs(num)<<'\n';
    }
    return 0;
}

3502. 不同路径数

3502. 不同路径数

题目要求:在一个n*m的矩阵中,每走一步可以添加一个数字,最终走完k步,一共可以构成多少个不同的数字?

n和m的数据范围非常小,最大只有5,而且k也很小,因此我们随便造就完了

很明显我们使用深搜。直接暴力搜索所有的数字即可,然后存在一个set中,最后返回set的元素数量。

#include <bits/stdc++.h>
using namespace std;
const int N=10;
int n,m,k;
int nums[N][N];
set<int> st;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
void dfs(int x,int y,int sum,int step){
    if (step>=k){
        //如果步数超限,则记录这个数字
        st.insert(sum);
        return;
    }
    for (int i=0;i<4;i++){
        int cx=x+dx[i],cy=y+dy[i];
        if (cx>=1 && cx<=n && cy>=1 && cy<=m){
            dfs(cx,cy,sum*10+nums[cx][cy],step+1);  //步数+1
            //更新当前的sum总和=sum*10+nums[cx][cy])(秦九韶算法)
        }
    }
}
int main(){
    cin>>n>>m>>k;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            cin>>nums[i][j];
        }
    }
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            //直接全部遍历不解释
            dfs(i,j,nums[i][j],0);
        }
    }
    cout<<st.size();
    return 0;
}

165. 小猫爬山

165. 小猫爬山

题目要求:有n个物品,每几个物品之间都可以放在一辆车上,前提是这几件物品的重量不能超过车的最大承受重量,每一辆车一美元,求得最少需要支付多少美元,才能运完这些全部的物品。


一看到这道题貌似就能看出可以用贪心来做。

即按照从大到小或者从小到大排序,然后如果超过了重量则新增一辆车。

但是!!贪心并不是最优的选择。为什么呢?

就像换硬币一样,我们贪心并不能得到最优的选择,动态规划才是最后的选择(我忘记哪道题了,有知道的大佬可以评论区回复我以下


因此我们选择深搜,并且这道题也是非常经典的一类深搜问题。

遍历所有的物品:

  • 如果当前物品可以放入这辆车,则放入这辆车,车辆总数不变,但是物品编号+1,表示开始下一个物品
  • 如果当前物品不能放入这辆车,则需要新增加一辆车,而且物品编号也要+1.
  • 每一个物品可以选择放入这辆车,也可以选择不放入,因此需要进行回溯
  • 剪枝:如果当前车辆数量超过了答案,则一定不是最优解
  • 当 最后一个物品也成功放入后,即 now-1==n ,则全部物品都放入,则记录答案。
#include <bits/stdc++.h>
using namespace std;
const int N=20;
int nums[N]; //每个物品的重量
int n,k;
int cnt;//车的总数量
int car[N]; //所有的车的载物情况
int ans=99999999;
void dfs(int now,int c){
    //now:当前物品
    //c:当前的车辆编号
    
    //剪枝
    if (c>=ans){
        //如果c超过了ans,则一定不是最优解
        return;
    }
    if (now-1==n){
        //所有的物品都遍历过了,则记录一个cnt数量
        ans=min(ans,c);
        return;
    }
    for (int i=1;i<=c;i++){//遍历所有的已经存在的车
        if (nums[now]+car[i]<=k){
            //now物品可以放在编号为i的这辆车上
            car[i]+=nums[now];
            dfs(now+1,c); //下一个物品,仍是当前车
            car[i]-=nums[now];//回溯
        }
    }
    //如果所有的物品都不能放在now这辆车上,则新增一辆车
    car[c+1]+=nums[now];
    dfs(now+1,c+1); //下一个物品,新增一辆车
    car[c+1]-=nums[now];//回溯
}
int main(){
    cin>>n>>k;//k是车最大承重 
    for (int i=1;i<=n;i++){
        cin>>nums[i];
    }
    dfs(1,0); 
    cout<<ans;
    
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

spring源码之扫描前设置

扫描前设置 &#x1f6f9;源码源码说明总结启动一个springboot项目源码 org.springframework.context.annotation.ComponentScanAnnotationParser#parse public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, String declaringClass) {// 创建C…

清明-微信小程序

# 云开发接入 初始化云开发 环境保密

深度学习部署(十三): CUDA RunTime API thread_layout线程布局

1. 知识点 在.vscode/settings.json中配置"*.cu": "cuda-cpp"可以实现对cuda的语法解析 layout是设置核函数执行的线程数&#xff0c;要明白最大值、block最大线程数、warpsize取值 maxGridSize对应gridDim的取值最大值maxThreadsDim对应blockDim的取值最…

酷炫的青蛇探针serverMmon

本文软件由网友 114514 推荐&#xff1b; 什么是 serverMmon &#xff1f; serverMmon (青蛇探针)是 nodeJs 开发的一个酷炫高逼格的云探针、云监控、服务器云监控、多服务器探针。 主要功能介绍&#xff1a; 全球服务器分布世界地图服务器&#xff08;控制端&#xff09; ping…

简单3招教你设置电脑时间

案例&#xff1a;电脑时间怎么设置&#xff1f; 【我使用电脑时&#xff0c;电脑显示的时间一直不对&#xff0c;这导致我非常不方便&#xff0c;想问下大家平常使用电脑时有什么设置电脑时间比较简单的方法吗&#xff1f;】 电脑的时间设置很重要&#xff0c;不仅可以保证电…

Java单例模式、阻塞队列、定时器、线程池

目录1. 单例模式1.1 饿汉模式实现单例1.2 懒汉模式实现单例1.2.1 加锁实现懒汉模式线程安全1.2.2 volatile实现懒汉模式线程安全1.3 饿汉模式和懒汉模式小结&#xff08;面试题&#xff09;2. 阻塞队列2.1 单线程下阻塞队列2.2 多线程下阻塞队列——生产者消费者模型2.3 模拟写…

【蓝桥集训18】二分图(2 / 2)

二分图定义&#xff1a;将所有点分成两个集合&#xff0c;使得所有边只出现在集合之间&#xff0c;就是二分图 目录 860. 染色法判定二分图 1、dfs 2、bfs 861. 二分图的最大匹配 - 匈牙利算法ntr算法 860. 染色法判定二分图 活动 - AcWing 1、dfs 思路&#xff1a; 对每…

白农:Imagination将继续致力于推进车规半导体IP技术创新和应用

4月2日Imagination中国董事长白农在中国电动汽车百人论坛上发表演讲&#xff0c;探讨了车规半导体核心IP技术如何推动汽车智能化发展&#xff0c;并接受了媒体采访。本次论坛上&#xff0c;他强调了IP技术在汽车产业链中日益重要的地位和供应商的位置前移。类比手机行业的发展&…

树、森林、二叉树:相互之间的转换

你好&#xff0c;我是王健伟。 前面我们讲过了各种二叉树&#xff0c;这方面的知识已经够多的了&#xff0c;本节就来讲一讲更通用的概念&#xff1a;树、森林以及与二叉树之间的转换问题。 树的存储结构 前面我们学习了树形结构的基本概念&#xff0c;在满足这个概念的前提…

python 包、模块学习总结

、模块基础 1、基本概念 模块是最高级别的程序组织单元&#xff0c;它将程序代码和数据封装起来以便重用。从实际角度来看&#xff0c;模块往往对应于python程序文件&#xff08;或是用外部语言如C、Java或C#编写而成的扩展&#xff09;。每一个文件都是一个模块&#xff0c;并…

小驰私房菜_11_mm-camera 添加客制化分辨率

#小驰私房菜# #mm-camera# #客制化分辨率# 本篇文章分下面几点展开&#xff1a; 1) mm-camera框架下&#xff0c;是在哪个文件添加客制化分辨率&#xff1f; 2&#xff09; 新添加分辨率的stall duration如何计算&#xff1f; 3&#xff09; 新添加的分辨率会有哪些影响&…

CentOS7操作系统离线安装docker

前言 有时候我们没有办法联网安装各种软件包&#xff0c;这时候就需要提前下载好所需要的包&#xff0c;然后把包上传到服务&#xff0c;在服务器上进行安装。 今天我们一起来探讨了在centos7操作系统上&#xff0c;安装docker。 专栏地址&#xff1a;容器管理 &#xff0c;…

ChatGLM-6B (介绍相关概念、基础环境搭建及部署)

文章目录前言一、ChatGLM-6B是什么&#xff1f;二、安装虚拟的python环境1.下载2.安装3.设置国内源(危险)4.虚拟环境使用简介三、部署ChatGLM-6B1. clone代码2. 运行1.创建虚拟环境2.装包2.1 找到合适的pytorch版本2.1 安装依赖2.2 验证pytorch是否为GPU版本3.运行四、部署过程…

银行数字化转型导师坚鹏:银行对公客户数字化场景营销案例萃取

银行对公客户数字化场景营销案例萃取与行动落地课程背景&#xff1a; 很多银行存在以下问题&#xff1a; 不清楚银行数字化营销与场景营销内涵&#xff1f; 不知道如何开展对公客户数字化营销工作&#xff1f; 不知道对公业务数字化场景营销成功案例&#xff1f; 学员收获&a…

5.39 综合案例2.0 - ESP32蓝牙遥控小车3(摇杆控制)

综合案例2.0 - 蓝牙遥控小车1- 摇杆控制成品展示案例说明器件说明小车连线小车源码PS2摇杆手柄遥控连线摇杆代码成品展示 案例说明 用STM32单片机做了一辆蓝牙控制的麦轮小车&#xff0c;分享一下小车的原理和制作过程。 控制部分分为手机APP&#xff0c;语音模块控制&#xf…

【AI绘图学习笔记】self-attention自注意力机制

台大李宏毅21年机器学习课程 self-attention和transformer 文章目录不同模态的输入和输出Sequence LabelingSelf-attentionMulti-head Self-attentionPositional EncodingSelf-attention的应用Self-attention对比其他算法vs CNNvs RNN总结不同模态的输入和输出 之前我们所讲的一…

SpringBoot学习笔记--数据库操作

文章目录7.1 JDBCHikariDataSource7.2 整合 Druid 到 Spring-Boot7.1 JDBCHikariDataSource 需求&#xff1a;演示 Spring Boot 如何通过 jdbcHikariDataSource 完成对 Mysql 操作 说明: HikariDataSource : 目前市面上非常优秀的数据源, 是 springboot2 第一步、创建测试数…

代码随想录Day44

今天继续学习通过动态规划解决问题 96.不同的二叉搜索树 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5 思路…

数据存储的细致介绍

本文介绍内容&#xff1a; 1&#xff1a;数据类型的详细介绍 2&#xff1a;整形的存储&#xff1a;原码&#xff0c;反码&#xff0c;补码 3&#xff1a;大小端字节序 4&#xff1a;浮点型的存储 一&#xff1a;数据类型的归类 1&#xff1a;整形家族(包括无符号&#xff09; …

Web 攻防之业务安全:本地加密传输测试.

Web 攻防之业务安全&#xff1a;本地加密传输测试. 业务安全是指保护业务系统免受安全威胁的措施或手段。广义的业务安全应包括业务运行的软硬件平台&#xff08;操作系统、数据库&#xff0c;中间件等&#xff09;、业务系统自身&#xff08;软件或设备&#xff09;、业务所提…