深度优先搜索(DFS)算法

本文介绍了深度优先搜索(DFS)的基本概念、递归实现方式,以及它在图遍历、迷宫求解、生成树和拓扑排序等领域的应用。通过两个编程示例,展示了DFS在全排列问题和自然数拆分问题中的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

深度优先搜索

是用来遍历或搜索树和图数据结构的算法,它是可以从任意跟节点开始,选择一条路径走到底,并通过回溯来访问所有节点的算法。

以我之见 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值