目录
同系列的文章——传送门
【蓝桥杯】DFS正确入门方式 ——基础入门模板(2)_小卢先冲的博客-CSDN博客第一题:[NOIP2002 普及组] 选数 、第二题:烤鸡 、 第三题:[NOIP2004 普及组] 火星人第四题:[NOIP2008 提高组] 火柴棒等式、第五题:PERKET、第六题:奇怪的电梯https://blog.csdn.net/weixin_61082895/article/details/129895135?spm=1001.2014.3001.5501
【蓝桥杯】DFS正确入门方式 ——基础入门模板(3)_小卢先冲的博客-CSDN博客第一题:入门迷宫问题、第二题:[USACO10OCT]Lake Counting S洪水灌溉问题、第三题:棋盘问题、第四题:[NOIP2001 提高组] 数的划分https://blog.csdn.net/weixin_61082895/article/details/129912846?spm=1001.2014.3001.5501
递推与递归 + DFS | 手把手带你画出递归搜索树_哔哩哔哩_bilibili
大佬的教学视频,非常细!
第一题:递归实现指数型枚举
题目描述
从 1∼n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。
输入格式
输入一个整数 n。
输出格式
每行输出一种方案。
同一行内的数必须升序排列,相邻两个数用恰好 11 个空格隔开。
对于没有选任何数的方案,输出空行。
本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。
数据范围
1≤n≤151≤n≤15
输入样例:
3
输出样例:
3 2 2 3 1 1 3 1 2 1 2 3
模板一:递归实现指数型枚举
题目分析
n个数,每一个数都有俩种可能(选和不选)
可采用dfs对所有的可能进行搜索
题目代码
import java.util.Scanner; public class Main { static int n; static int N = 20; static int st[]; //记录每一个数的状态,0表示还没考虑,1表示选这个数,2表示不选这个数。 public static void main(String[] args) { st = new int[N]; Scanner sca = new Scanner(System.in); n = sca.nextInt(); dfs(1); } static void dfs(int x) {//x表示当前枚举到了哪个位置 if (x > 3) {//结束这一次的循环,并且输出 for (int i = 1; i <= n; i++) { if (st[i] == 1) { System.out.print(i + " "); } } System.out.println(); return; } //选 st[x] = 1; dfs(x + 1);//下一个位置 st[x] = 0;//每当上一个数的循环结束,都要恢复现场,因为每个数都有俩种选择选和不选 //不选 st[x] = 2; dfs(x + 1); st[x] = 0;//恢复现场 } }
第二题:全排列问题
题目描述
按照字典序输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
输入格式
一个整数 n。
输出格式
由 1∼n 组成的所有不重复的数字序列,每行一个序列。
每个数字保留 5 个场宽。
输入输出样例
输入
3
输出1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1说明/提示
1≤n≤9。
模板二:全排列问题
题目分析
依次枚举每个位置放哪个数
题目代码
import java.util.Scanner; public class 全排列问题 { static int N = 10; static int n; static Boolean st[];//false表示没有选这个数,true表示选了这个数 static int arr[];//用来存答案。也就是123/132/321 public static void main(String[] args) { st = new Boolean[N]; for (int i = 0; i < st.length; i++) {//初始化st为false,都没选 st[i] = false; } arr = new int[N]; Scanner sca = new Scanner(System.in); n = sca.nextInt(); dfs(1); } static void dfs(int x) {//x表示当前枚举到了哪个位置 if (x > n) { for (int i = 1; i <= n; i++) { System.out.printf("%5d",arr[i]); } System.out.println(); return; } for (int i = 1; i <= n; i++) { if (!st[i]){ st[i] = true; arr[x] = i; dfs(x + 1);//下一个位置 st[i] = false;//恢复现场 arr[x] = 0; } } } }
第三题:组合的输出
题目描述
排列与组合是常用的数学方法,其中组合就是从 n 个元素中抽出 r 个元素(不分顺序且 r≤n),我们可以简单地将 n 个元素理解为自然数 1,2,…,n,从中任取 rr 个数。
现要求你输出所有组合。
例如 n=5,r=3,所有组合为:
123,124,125,134,135,145,234,235,245,345
输入格式
一行两个自然数 (1<n<21,0≤r≤n)。
输出格式
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。
注意哦!输出时,每个数字需要 33 个场宽。以 C++ 为例,你可以使用下列代码:
cout << setw(3) << x;
输出占 33 个场宽的数 xx。注意你需要头文件
iomanip
。输入输出样例
输入
5 3输出
1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
模板三:组合型问题
题目分析
依次枚举每个位置放哪个数
题目代码
import javax.xml.stream.FactoryConfigurationError; import java.util.Scanner; public class 组合的输出 { static int n, r; static int arr[];//记录都选了那些数 public static void main(String[] args) { arr = new int[25]; Scanner sca = new Scanner(System.in); n = sca.nextInt(); r = sca.nextInt(); dfs(1, 1); } //x记录当前枚举到了哪个位置,start记录当前位置从几开始枚举 static void dfs(int x, int start) { if (x > r) { for (int i = 1; i <= r; i++) { System.out.printf("%3d", arr[i]); } System.out.println(); return; } for (int i = start; i <= n; i++) { arr[x] = i; dfs(x + 1, i+ 1); arr[x] = 0;//恢复现场 } } }