深度优先搜索
是用来遍历或搜索树和图数据结构的算法,它是可以从任意跟节点开始,选择一条路径走到底,并通过回溯来访问所有节点的算法。
以我之见 Dfs思修基于递归思想,通过递归的形式来缩小问题规模,把一件事分割成若干个相同的小事,逐步完成。就像不撞南墙不回头.
深度优先搜索的步骤分为 1.递归下去 2.回溯上来
DFS的应用
DFS在很多领域有广泛的应用,包括但不限于以下几个方面:
- 图的遍历:通过DFS可以遍历图中所有节点,查找特定节点或寻找连通分量。
- 迷宫求解:DFS可以用于解决迷宫问题,找到从起点到终点的路径。
- 生成树:DFS可以生成最小生成树,如Prim算法和Kruskal算法。
- 拓扑排序:DFS可以用于拓扑排序,找到有向无环图的节点排序。
DFS的具体运用
P1706 全排列问题
题目描述
按照字典序输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
输入格式
一个整数 n。
输出格式
由 1∼n 组成的所有不重复的数字序列,每行一个序列。
分析: 也就是从第一个位置开始遍历所有可能的数字,将每个未被使用过的数字加入当前排列中,并继续递归搜索下一个位置。在搜索过程中,通过使用一个布尔数组来记录数字的使用情况,以确保生成的排列不重复。当搜索到最后一个位置时,即得到一个完整的排列,我们将其输出。然后进行回溯操作,将当前位置的数字重新标记为未使用,以便尝试其他可能的数字。
#include <stdio.h>
#include <stdbool.h>
#define MAXN 10
bool used[MAXN]; // 记录数字是否已被使用
int ans[MAXN]; // 存储当前排列结果
int n;
void dfs(int depth) {
if (depth == n + 1) { // 已经得到一个完整的排列
for (int i = 1; i <= n; i++) {
printf("%5d", ans[i]);
}
printf("\n");
return;
}
for (int i = 1; i <= n; i++) {
if (!used[i]) { // 数字i未被使用
ans[depth] = i; // 将数字i加入当前排列中
used[i] = true; // 标记数字i已被使用
dfs(depth + 1); // 继续搜索下一个位置
used[i] = false; // 回溯,将数字i重新标记为未使用
}
}
}
int main() {
printf("请输入整数n:");
scanf("%d", &n);
dfs(1); // 从第一个位置开始搜索
return 0;
}
P2404 自然数的拆分问题
题目描述
任何一个大于 1 的自然数 n,总可以拆分成若干个小于 n 的自然数之和。现在给你一个自然数 n,要求你求出 n 的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。
输入格式
输入:待拆分的自然数 n。
输出格式
输出:若干数的加法式子。
#include<stdio.h>
int a[100];
int n;
void print(int j)//输出数据
{
for (int i = 0; i <= j; i++)
{
if (i == 0) printf("%d", a[i]);
else printf("+%d", a[i]);
}
printf("\n");
}
void search(int sum, int j, int s)//dfs深搜
{
for (int i = s; i < n; i++)//从第s个开始搜,i=s保证是升序
{
sum += i;
if (sum > n) return;
if (sum == n) { a[j] = i; print(j); return; }
a[j] = i;
search(sum, j + 1, i);
sum -= i;//回溯
}
}
int main()
{
scanf_s("%d", &n);
search(0, 0, 1);
return 0;
}