C++:第十一讲DFS深搜

news2025/1/23 12:16:47

Everyday English

Your optimal career is simply this: Share the real you with physical world through th e process of creative self-expression.
你的最佳职业很简单,就是这样:通过创造性自我表达的途径和世界分享真实的你。

前言

今天带着大家学习一个既简单又重要的算法——深搜函数DFS。

DFS

一、基本思想

  1. 为了求得问题的解,先选择某一种可能情况向前探索;
  2. 在探索过程中,一旦发现原来的选择是错误的,就退回一步重新选择,继续向前探索;
  3. 如此反复进行,直至得到解或证明无解

二、搜索算法

搜索算法,就是利用计算机的高性能,对问题的“状态空间”进行枚举,穷举出一个问题的全部或者部分可能的情况,找到最优解或者统计合法解的个数。        在搜索算法中,深度优先搜索算法(Depth First Search,DFS,简称深搜),常常指利用递归函数方便地实现暴力枚举的算法,也称为“回溯法”。通过递归函数,我们可以逐层地枚举每一种可能,从而实现枚举所有可能的“状态”。       搜索算法是一些高级算法的基础,而搜索算法可以在很多问题中解决数据范围较小的部分。掌握正确的写搜索算法,对后续高级算法的学习和理解有着一定的帮助。

三、深搜模版(C++)

vector<int> a; // 记录每次排列 
vector<int> book; //标记是否被访问 

void DFS(int cur, int k, vector<int>& nums){
    if(cur == k){ //k个数已经选完,可以进行输出等相关操作 
        for(int i = 0; i < cur; i++){
			printf("%d ", a[i]);
		} 
        return ;
    }
    for(int i = 0; i < k; i++){ //遍历 n个数,并从中选择k个数 
        if(book[nums[i]] == 0){ //若没有被访问
            a.push_back(nums[i]); //选定本输,并加入数组 
            book[nums[i]] = 1; //标记已被访问 
            DFS(cur + 1, n, nums); //递归,cur+1 
            book[nums[i]] = 0; //释放,标记为没被访问,方便下次引用 
            a.pop_back(); //弹出刚刚标记为未访问的数
        }
    }
}

例题(洛谷P1706全排列问题)

题目描述

按照字典序输出自然数 1到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

一个整数n。

输出格式

由1∼n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 5个场宽。

输入输出样例

输入 #1

3

输出 #1

    1    2    3
    1    3    2
    2    1    3
    2    3    1
    3    1    2
    3    2    1

说明/提示

1≤n≤9。

解题思路

根据题意,对于全排列问题,以样例n=3为例,可以深度优先DFS搜索方法如图所示。

根据上述搜索过程,设计算法步骤如下:(1)用数组a保存排列,当排列的长度为n时,是一种排列方案,输出即可。(2)用数组vis记录数字是否被使用过,当vis[i]=1时,表示数字i被使用过,否则没有被使用过。 (3)DFS(u)表示已经确定了a的前u个数(从a[1]开始填数),当u>n时,输出搜索的全排列。 注意:在DFS过程中,数组vis既要标记,也要“撤销”标记。

AC 

#include<bits/stdc++.h>
using namespace std;
int a[10],n;
bool vis[10];
void dfs(int u){
	if(u>n){//当u=n+1时,表示前n个空位已填好数 
		for(int i=1;i<=n;i++){//输出一种排列方案 
			cout<<setw(5)<<a[i];
		}
		cout<<endl;
		return;//dfs的终止条件 
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			a[u]=i;//在第u个空位填上i 
			vis[i]=1;//标记i为已使用 
			dfs(u+1);//填下一个空位 
			vis[i]=0;//dfs回来后,要撤销之前的标记 
		}
	}
}
int main(){
	cin>>n;
	dfs(1);
	return 0;
}

setw函数

格式:
setw(……)//()内是数字
setw()——打印格式(控制)
setw means:宽度
E.X.
setw(4):
0   0   0   0//每个隔4格
!只适用于打印字符!

洛谷小课堂P1605 迷宫

题目描述

给定一个 N×M 方格的迷宫,迷宫里有T处障碍,障碍处不可通过。

在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。

给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。

输入格式

第一行为三个正整数 N,M,T,分别表示迷宫的长宽和障碍总数。

第二行为四个正整数 SX,SY,FX,FY,SX,SY 代表起点坐标,FX,FY 代表终点坐标。

接下来 T 行,每行两个正整数,表示障碍点的坐标。

输出格式

输出从起点坐标到终点坐标的方案总数。

输入输出样例:

输入 #1

2 2 1
1 1 2 2
1 2

输出 #1

1

说明/提示

对于 100%的数据,1≤N,M≤5,1≤T≤10,1≤SX,FX≤n,1≤SY,FY≤m。

解题思路

这题除了深搜,还是深搜。

深搜,一句话来总结一下,就是:

不撞南墙不回头

而在这题里,“南墙”有三个:

第一个是真墙:迷宫的围墙

也就是俗话所说的越界。越界了你还不回头,你是想去哪儿?

第二个是山墙:障碍物T

如果一障碍物横在你面前,你还是绕路吧!

第三个是人造墙:题目说了每个方格最多只能走一次

这是真没办法

所以深搜的返回条件就出来了——就是以上那三堵墙

我们每次可以从上下左右四个方向进行深搜,一旦遇上南墙就返回。

AC

#include<iostream>
using namespace std;
int n, m, t, sx, sy, fx, fy;
int  vis[10][10]; //标记
int mp[10][10]; //障碍物位置
int ans = 0;
int xx[] = { 1,0,-1,0 };
int yy[] = { 0,-1,0,1 };
void dfs(int x, int y)
{
    if (x == fx && y == fy)
    {
        ans++;
        return;
    }
    for (int i = 0; i < 4; i++)
    {
        int dx = xx[i] + x;
        int dy = yy[i] + y;
        if (dx >= 1 && dx <= n && dy >= 1 && dy <= m && vis[dx][dy]==0 && mp[dx][dy]==0)
        {
            vis[dx][dy] = 1;
            dfs(dx, dy);
            vis[dx][dy] = 0;
        }
    }
}
int main()
{
    cin >> n >> m >> t >> sx >> sy >> fx >> fy;
    while (t--)
    {
        int a, b;
        cin >> a >> b;
        mp[a][b] = 1;
    }
    vis[sx][sy] = 1;
    dfs(sx, sy);
    cout << ans << endl;
    return 0;
}

课后练习:洛谷P2404 自然数的拆分问题

题目

自然数的拆分问题 - 洛谷

解题思路

dfs递归求解,假设1到n-1每个数都有n个,现在在这n(n-1)个数里选取任意个数字,使这些数字的和为n,因此这n(n-1)个数只有选和不选两种状态,正是dfs的经典应用,得到的结果可能会有重复的

所有可以用sort和set进行排序和去重步骤

AC

#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
vector<int>a;
string midd;
set<string>h;
int n,t;
 
void dfs(int mid){
    if(mid==n){         //如果数的累加和等于n就记录该组合
        t++;
        vector<int>b(a);   //复制数组a
        sort(b.begin(),b.end());     //排序
        midd.clear();
        for(int i=0;i<b.size();i++){          //把整数数组转换成字符串,并存入set里去重
            midd+=(b[i]+'0');
            if(i<b.size()-1) midd+='+';
        }
        h.insert(midd);
    }
 
    for(int i=1;i<n;i++){
        if(mid+i<=n){
            mid+=i;
            a.push_back(i);
            dfs(mid);               //每一层都加入i并递归到下一层(选)
            a.pop_back();           //回溯,使得这一层不加入i(不选)
            mid-=i;
        }
    }
}
 
int main(){
    cin>>n;
    dfs(0);
    for(auto i:h)
      cout<<i<<endl;
 
    return 0;
}

结尾

本篇文章共3767字,如果你能支持一下我,我十分感谢!!!

如果你喜欢或想了解一下其他的算法,可以看看以下这些:

二分:

C++:第十讲二分查找-CSDN博客

前缀和与差分:

C++:第九讲前缀和与差分-CSDN博客

排序:

C++:第七讲冒泡排序-CSDN博客

函数:

C++第6讲max和min函数_c++ min函数-CSDN博客

C++第五讲函数初步-CSDN博客

for循环&数组:

C++第四讲for循环及数组-CSDN博客

if语句&else语句及运算:

C++第三讲:C++中的逻辑运算符及if else语句-CSDN博客

基础:

C++第二讲输入与输出-CSDN博客

C++第一讲认识C++编译器-CSDN博客

最后认识一下,我是爱编程的喷火龙廖,我们有缘再见!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【音视频 ffmpeg 学习】 跑示例程序 持续更新中

环境准备 在上一篇文章 把mux.c 拷贝到main.c 中 使用 attribute(unused) 消除警告 __attribute__(unused)/** Copyright (c) 2003 Fabrice Bellard** Permission is hereby granted, free of charge, to any person obtaining a copy* of this software and associated docu…

scanf函数返回值被忽略

心怀希望的前进 前言 最近在复习c语言&#xff0c;发现了许多之前不了解的知识&#xff0c;今天想来与大家分享一下scanf返回值值被忽略的问题。 很多人应该都在vs中见到过&#xff0c;我们先说原因&#xff0c;再说改进方法 原因&#xff1a; scanf函数在读取数据时不会检…

kafka实现延迟消息

背景 我们知道消息中间件mq是支持延迟消息的发送功能的&#xff0c;但是kafka不支持这种直接的用法&#xff0c;所以我们需要独立实现这个功能&#xff0c;以下是在kafka中实现消息延时投递功能的一种方案 kafka实现延时消息 主要的思路是增加一个检测服务&#xff0c;这个检…

Python武器库开发-武器库篇之上传本地仓库到Git(三十八)

武器库篇之上传本地仓库到Git(三十八) 当我们在Git中创建远程仓库和进行了SSH key免密登陆之后&#xff0c;我们点击 Your respositories 可以查看我们所创建的远程仓库&#xff0c;如图所示&#xff1a; 如果我们需要将本地的仓库上传到Git&#xff0c;首先我们需要建立一个本…

数据结构与算法 - 查找

文章目录 第1关&#xff1a;实现折半查找第2关&#xff1a;实现散列查找 第1关&#xff1a;实现折半查找 代码如下&#xff1a; /*************************************************************date: April 2009copyright: Zhu EnDO NOT distribute this code. ***********…

Python实现的面部健康特征识别系统

Python实现的面部健康特征识别系统 引言1. 数据集获取与准备2. 模型训练3. Flask框架的应用4. 前台识别测试界面 结论与展望 引言 本文将介绍一个基于Python的面部健康特征判别系统&#xff0c;该系统利用互联网获取的公开数据集&#xff0c;分为健康、亚健康和不健康三个类别…

蓝牙曝底层安全漏洞,数十亿设备受影响

内容概括&#xff1a; Eurecom的研究人员近期分享了六种新型攻击方式&#xff0c;统称为"BLUFFS"&#xff0c;这些攻击方式能够破坏蓝牙会话的保密性&#xff0c;使设备容易受到冒充和中间人攻击(MitM)。攻击发现者Daniele Antonioli解释道&#xff0c;"BLUFFS…

Sentinel-3如何处理并下载LST数据-陆地表面温度”(Land Surface Temperature)

LST 通常指的是“陆地表面温度”&#xff08;Land Surface Temperature&#xff09;。陆地表面温度是指地球表面上陆地部分的温度&#xff0c;而不包括水体表面。LST 是遥感技术中一个重要的参数&#xff0c;可以通过卫星遥感等手段进行测量和监测。 陆地表面温度对于许多领域…

WPF 漂亮长方体、正文体简单实现方法 Path实现长方体 正方体方案 WPF快速实现长方体、正方体的方法源代码

这段XAML代码在WPF中实现了一个类似长方体视觉效果的图形 声明式绘制&#xff1a;通过Path、PathGeometry和PathFigure等元素组合&#xff0c;能够以声明方式精确描述长方体每个面的位置和形状&#xff0c;无需编写复杂的绘图逻辑&#xff0c;清晰直观。 层次结构与ZIndex控制…

利用 IntelliJ IDEA 整合 GitHub 实现项目版本控制与协作管理

目录 前言1 设置GitHub登录账号2 将项目分享到GitHub3 IntelliJ IDEA 中导入Github项目4 往GitHub推送代码4.1 Commit Change&#xff08;提交到本地库&#xff09;4.2 Git -> Repository -> Push&#xff08;推送到远程库&#xff09; 5 拉取远程库代码到本地6 克隆远程…

Python列表的介绍与操作 增改查,连接,赋值,复制,清空

列表 在日常中我们通过给变量赋值来存储数据,比如 a "hello" b "world" c "你好啊" d "....."由于变量一次只能存储一个数据,但我们如果想一次存储多个数据,的话这样存储会很复杂,所以,我们可以通过列表 列表(List)是Python中的…

彻底解决可视化:中文字体显示「豆腐块」问题!

问题复现 # 导入必要的包 library(ggplot2)# 设置主题样式 theme_set(theme_minimal(base_size 15))# 创建一个简单的折线图 ggplot(data data.frame(x c(1, 2, 3), y c(1, 2, 3)), aes(x x, y y)) geom_line(color "blue") labs(title "欢迎关注公众号…

鸿蒙HarmonyOS-图表应用

简介 随着移动应用的不断发展&#xff0c;数据可视化成为提高用户体验和数据交流的重要手段之一。在HarmonyOS应用开发中&#xff0c;一个强大而灵活的图表库是实现这一目标的关键。而MPChart就是这样一款图表库&#xff0c;它为开发者提供了丰富的功能和灵活性&#xff0c;使得…

从0到1浅析Redis服务器反弹Shell那些事

文章目录 前言Redis服务1.1 特点与应用1.2 安装与使用1.3 语法和配置1.4 未授权访问 反弹Shell2.1 Web服务写入Webshell2.2 Linux定时任务反弹shell2.3 /etc/profile.d->反弹shell2.4 写入ssh公钥登录服务器2.5 利用Redis主从复制RCE2.6 SSRF漏洞组合拳->RCE 总结 前言 …

ES6之解构赋值详解

✨ 专栏介绍 在现代Web开发中&#xff0c;JavaScript已经成为了不可或缺的一部分。它不仅可以为网页增加交互性和动态性&#xff0c;还可以在后端开发中使用Node.js构建高效的服务器端应用程序。作为一种灵活且易学的脚本语言&#xff0c;JavaScript具有广泛的应用场景&#x…

网络交换机端口管理会面临的问题

交换机端口管理是跟踪网络交换机及其端口连接详细信息的过程&#xff0c;在大型网络中&#xff0c;交换机端口管理过程通常使用自动化交换机端口管理工具执行。 通过网络交换机端口提供的完全控制和可见性使交换机端口管理工具在管理网络时必不可少&#xff0c;在网络中部署交…

【Java开发岗面试】八股文—Java基础集合多线程

声明&#xff1a; 背景&#xff1a;本人为24届双非硕校招生&#xff0c;已经完整经历了一次秋招&#xff0c;拿到了三个offer。本专题旨在分享自己的一些Java开发岗面试经验&#xff08;主要是校招&#xff09;&#xff0c;包括我自己总结的八股文、算法、项目介绍、HR面和面试…

苹果电脑Dock栏优化软件 mac功能亮点

hyperdock mac是一款Dock优化软件&#xff0c;hyperdock支持使用窗口自动排列功能&#xff0c;您可以直接通过将窗口拖拉至屏幕上方来快速最大化至全屏&#xff0c;又或者拖动到左右来进行左分屏和右分屏。而且Dock优化软件还有一个特色便是对Dock的强大管理哪里能力&#xff0…

【软件工程】走近演化过程模型:软件开发的不断进化之路

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 软件工程 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言&#xff1a; 正文 演化过程模型&#xff08;Evolutionary Model&#xff09; 介绍&#xff1a; 解释&#xff1a; 优缺点&#x…

Android—— MIPI屏调试

一、实现步骤 1、在kernel/arch/arm/boot/dts/lcd-box.dtsi文件中打开&dsi0节点&#xff0c;关闭其他显示面板接口&#xff08;&edp_panel、&lvds_panel&#xff09; --- a/kernel/arch/arm/boot/dts/lcd-box.dtsib/kernel/arch/arm/boot/dts/lcd-box.dtsi-5,14 …