dfs入门排列数字问题

  • dfs入门排列数字问题
    • 一、问题概述
    • 二、问题分析
    • 三、代码分析
      • (一)、如何表示填写完成
      • (二)、如何判断该填哪个数
      • (三)、如何表示填空
      • (四)、实现dfs
    • 四、代码全览
    • 五、问题升级
    • 六、作者相关
      • (一)、作者简介
      • (二)、联系方式

dfs入门排列数字问题

一、问题概述

给定一个正整数n,将数字1~n排成一排有很多种排列方法。要求输出所有的排列方案。
先上例题链接:https://www.acwing.com/problem/content/844/

以下内容截取至ACwing网站中例题链接里那个网页
给定一个整数 n,将数字 1∼n 排成一排,将会有很多种排列方法。
现在,请你按照字典序将所有的排列方法输出。

输入格式
共一行,包含一个整数 n。
输出格式
按字典序输出所有排列方案,每个方案占一行。

二、问题分析

先看一波示例:如输入3,则按字典序输出:

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

分析一波输出,发现输出是一组排列输出结束,再输出另一种排列。当然我们思考时也可以这样思考,这也就是 进入dfs [Depth-First-Search](深度优先搜索)的第一步,即,先把一种情况考虑完再考虑下一种可能的情况
我们看输入为三的情况:

需要填写三个空来完成排列。按深搜的思路,应该是先找出一组后再找下一组。如图中红色路径:

首先三个空都未填满数字,先填第一个空,填为“1”;
然后填第二个空,填为“2”;
再填写第三个空,为“3”;
此时都已经填写完成,输出这一组结果
这一组处理结束,则回溯到上一个可以操作的节点;
然后再次填写…(发现了没,这其实是一个递归)

三、代码分析

(一)、如何表示填写完成

当然是判断当前填到第几个空是否和需要填的空相等判断。

(二)、如何判断该填哪个数

由于每个数只能使用一次,所以我们可以用一个 bool 数组(hasUsed)来标记接下来哪个数可以被填入空中。要注意的是,在填完一组后,回溯时要把相应标记重置为未使用状态。

(三)、如何表示填空

同样,我们可以使用一个 int 数组(path)来表示待填的空。

(四)、实现dfs

如图,我们可以先在用for循环模拟填一个空的数,然后再递归的填写不同的空,伪代码如下:

dfs (start, end)if start == endoutputreturnfor  i, 1 : nif ( ! hasUsed[i])path[start] = imark hasUsed[i]dfs(start + 1, end)clear mark hasUsed[i]

如图为伪代码的解释:

图中“已用”, “可用” 为hasUsed数组中的状态;
图中for循环中的1, 2, 3为遍历可能填入空中的数;
图中红色部分为一组填写完成,进行下一组填写。

注意,填满后回溯时要将结束使用的数恢复到未使用状态!!!
以下为dfs函数的代码:

//       当前该填的空    需要填的空
void dfs (int start, int end)
{if (start == end){for (int i = 0; i < end; i++)cout << path[i] << " ";cout << endl;return;}// 从1开始填for (int i = 1; i <= end; i++)// 如果这个数被用过,则看下一个可能的数是否被用过if (!hasUsed[i]){// 如果没被使用,则填入数字path[start] = i;hasUsed[i] = true;dfs(start + 1, end);    // 递归的填下一个空hasUsed[i] = false;       // 不能忘记重置标记}
}

四、代码全览

好了,接下来可以看一下完整代码了。

// 深度优先搜索  排列数字
#include <iostream>
#define MAXN 10
using namespace std;bool hasUsed[MAXN];    // 标记各个数位是否被使用
int path[MAXN];     // 存储可能的序列
void dfs (int, int);int main (void)
{int n = 0;cin >> n;dfs(0, n);return 0;
}//       当前该填的空    需要填的空
void dfs (int start, int end)
{if (start == end){for (int i = 0; i < end; i++)cout << path[i] << " ";cout << endl;return;}// 从1开始填for (int i = 1; i <= end; i++)// 如果这个数被用过,则看下一个可能的数是否被用过if (!hasUsed[i]){// 如果没被使用,则填入数字path[start] = i;hasUsed[i] = true;dfs(start + 1, end);    // 递归的填下一个空hasUsed[i] = false;       // 不能忘记重置标记}
}

五、问题升级

如果这个理解的差不多的话可以试一下这个问题的哦:
https://www.acwing.com/problem/content/95/

摘自Acwing题目描述:
从 1∼n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。

输入格式 两个整数 n,m ,在同一行用空格隔开。

输出格式 按照从小到大的顺序输出所有方案,每行 1 个。

首先,同一行内的数升序排列,相邻两个数用一个空格隔开。

其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。

该题的一个代码:

#include <iostream>
#define MAXN 50using namespace std;int path[MAXN];
bool hasUsed[MAXN];
void dfs(int start, int end, int n);int main (void)
{int n, m;cin >> n >> m;dfs(0, m, n);return 0;
}void dfs(int start, int end, int n)
{if (start == end){for (int i = 0; i < end; i++)cout << path[i] << " ";cout << endl;return;}else{for (int i = 1; i <= n; i++){path[start] = i;if (start >= 1 && path[start - 1] >= path[start])continue;hasUsed[i] = true;dfs(start + 1, end, n);hasUsed[i] = false;}}
}

六、作者相关

  • (一)、作者简介

    • 作者:馗顺先生
    • 简介:一个热爱程序设计与电子技术的预备猿。后续也会不定期更新一些有趣的代码,以及一些有用的算法实现。大家可以关注以下哦。最后,若有不足,希望各位大佬们不吝赐教。
  • (二)、联系方式

    • 邮箱:2727144006@qq.com
    • 博客地址: https://blog.csdn.net/qq_33519837?spm=1001.2100.3001.5113

dfs入门排列数字问题(一看就懂的讲解)相关推荐

  1. bfs迷宫寻路问题(一看就懂的讲解)

    bfs迷宫问题讲解 广度优先搜索解决迷宫寻路问题 一.问题概述 二.问题分析 (一).手动模拟 (二).如何用计算机来解决 (1).地图表示 (2).如何找通路 (3).==如何找最短路(难点)== ...

  2. 小学生都看得懂的C语言入门(1): 基础/判别/循环

    c基础入门, 小学生也可以都看得懂!!!! 安装一个编译器, 这方面我不太懂, 安装了DEV-C++  ,体积不大,30M左右吧, 感觉挺好用,初学者够了. 介绍下DEV 的快键键: 恢复 Ctrl+ ...

  3. DFS和BFS概念及实践+acwing 842 排列数字(dfs) +acwing 844. 走迷宫(bfs)

    DFS (深搜), 也有说就是递归的 执着: 一直搜到底,然后回溯下一个节点 数据结构 : stack (这里的栈,实际上是编译器内部的栈, 所以说也可以看成递归, 递归内部也是调用编译器内部栈) 空 ...

  4. 《零基础看得懂的C++入门教程 》——(3)表达式花样挺多鸭

    一.学习目标 了解变量之间的计算 了解什么是表达式 了解什么是自增.自减 目录 预备第一篇,使用软件介绍在这一篇,C++与C使用的软件是一样的,查看这篇即可:<软件介绍> 想了解编译原理和 ...

  5. 《零基础看得懂的C++入门教程 》——(2)什么是数据类型、变量?一看便会

    一.学习目标 了解基本常用的数据类型 了解什么是变量 目录 预备第一篇,使用软件介绍在这一篇,C++与C使用的软件是一样的,查看这篇即可:<软件介绍> 想了解编译原理和学习方法点这篇,学习 ...

  6. 《假如编程是魔法之零基础看得懂的Python入门教程 》——(七)我把魔法变成了积木

    学习目标 了解魔法积木的使用--自定义函数 了解魔法积木的结果反馈--自定义函数返回值 了解魔法积木的原料传递--自定义函数传参 了解魔法积木的类型分类--类与对象 推荐 1.<备受好评的看得懂 ...

  7. 《假如编程是魔法之零基础看得懂的Python入门教程 》——(六)精简魔法更强大

    学习目标 了解对相似逻辑的简化编写--循环 推荐 1.<备受好评的看得懂的C语言入门教程> 目录 第一篇:<假如编程是魔法之零基础看得懂的Python入门教程 >--(一)既然 ...

  8. 《假如编程是魔法之零基础看得懂的Python入门教程 》——(五)我的魔法竟然有了一丝逻辑

    学习目标 了解魔法世界中的结构表现--缩进 了解魔法世界的逻辑判断--if 了解魔法世界的多次逻辑判断--ifelse嵌套 了解魔法世界中的逻辑运算--且 and 与或 or 推荐 1.<备受好 ...

  9. ---排列数字---

    排列数字(回溯的应用) 题目链接,点击直达 题解: 1.用path数组来保存排列 2.bool st[]数组来标识当前数字是否被用过 3.dfs继续递归下一层 4,恢复现场,第 i 个位置填写某个数字 ...

最新文章

  1. mysql索引优化规则_Mysql优化选择最佳索引规则
  2. sql大于某个时间_学习SQL-复杂查询
  3. 【算法随记一】Canny边缘检测算法实现和优化分析。
  4. 一年学遍吴恩达、李飞飞、周志华等16大精品课!(ML、CV、NLP一应俱全)
  5. Adobe AIR for html/js人员
  6. 字节跳动算法工程师总结:中高级java开发面试题
  7. 拓端tecdat|R语言POT超阈值模型和极值理论EVT分析
  8. eclipse下载支持compiler compliance level 1.8的插件
  9. android模拟器命令行,夜神安卓模拟器命令行整理贴
  10. 朝阳正规的计算机学校有哪些,朝阳都有哪些专科学校
  11. 本科的控制工程到底学什么?
  12. 前端资源汇总-酷站分享[转载]
  13. asp.net开发wap程序必备:识别来访手机品牌型号【来源网络】
  14. 数据库系统的核心:数据模型
  15. 360怎样修改wifi服务器地址,360路由器怎么重新设置?
  16. 5 个市值较小的去中心化游戏
  17. 安卓手机卡顿怎么解决_苹果七系统内存满了手机卡顿解决方法
  18. GitChat,一个记录技术和躺着赚零花钱的免费平台
  19. Android之手机卫士涉及的知识点总结
  20. 关于数据库系统的学习

热门文章

  1. android开发toast通知,Toast Notifications
  2. python组件的react实现_React-Router动态路由设计最佳实践
  3. druid连接池_c3p0、dbcp、druid 三大连接池对比
  4. python常用类库_Python常用库
  5. dos配置java_windows dos命令配置JAVA环境变量
  6. 一年后斩获腾讯T3,层层深入
  7. Unet实现图像分割(三)
  8. hplus java,hplus
  9. 前端运行python代码几种方式_前的解释|前的意思|汉典“前”字的基本解释
  10. ipconfig不是内部或外部_OSPF外部路由详解-LSA4-LSA5