算法——使用DFS解决全排列问题

什么是 DFS

​ DFS 是深度优先遍历,将序列抽象成树状结构,以优先深度的方式进行遍历,获取想要的结果

例如

​ 假设一个树的结构如下:

       1 
     2   3
   4  5 5  7

​ 使用深度优先遍历的遍历顺序就是1->2->4->5->3->5->7,也就是说,深度优先遍历会从根节点root开始,以深度优先遍历到其一个 不能再继续向下遍历 的子孙节点,然后回溯到该节点的父节点,再重复向下遍历和回溯的过程

优缺点

​ DFS 的优点是,使用 DFS 进行遍历,空间的占用是O(h)(h 为树的高度)级别的,因为空间占有最多的时候,也就是遍历到最深的叶子节点时,此时空间的使用是等于树的高度的

​ 而由于 DFS 执着与向下搜索,可能会错过更近的答案,从而浪费运算的时间,即如果树的第二层和第五层都存在答案,DFS 可能会先找到第五层的目标而不是第二层的

例子

​ 这是一道全排列问题,即给定n,我们要给出1 ~ n这些数字所能排列出的所有情况,这里1 ≤ n ≤ 7

思考

​ 首先考虑思路,全排列问题是经典的 DFS 问题,假定n = 3,我们要给出1 ~ 3的全排列,正确结果如下:

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

​ 我们可以把它抽象为一个树,我们首先考虑第一位的元素,有三种情况1、2、3,这就是树的三个分支,再考虑1的分支的第二位,有12、13两种情况,这两种情况又是1的两个分支,在考虑12,只剩123一种情况了,到此,从1开始的一个分支就彻底结束了,我们也得到了全排列的第一个情况

​ 这是我们还位于123,下一步就是回溯,向上回溯,首先来到12,我们发现它只有123一个分支,已经被遍历完了,所以继续向上回溯,来到1,我们发现它还有一个13分支没有遍历,我们就继续遍历13,如此一直重复下去,直到所有的分支都遍历结束后,我们也就得到了全排列的全部结果

代码 + 注释

#include<iostream>

using namespace std;

const int N = 10;

int n;
// 用来存储结果的数组
int path[N];
// 用来标志元素是否被使用过的数组
bool st[N];

void dfs(int u) {
    // 如果 dfs 层数 == 最大深度,就输出这种情况
    if (u == n) {
        for (int i = 0; i < n; i++)
            printf("%d ", path[i]);
        return;
    }
    // 深度优先遍历
    for (int i = 1; i <= n; i++) {
        // 每遍历到一个元素,先检测是否重复
        if (!st[i]) {
            // 设定当前位置的值
            path[u] = i;
            // 将这个值标记为已用
            st[i] = true;
            // 继续向下遍历
            dfs(u + 1);
            // 恢复原样
            st[i] = false;
        }
    }
}

int main() {
    cin >> n;
    // 从 0 开始 DFS
    dfs(0);
}
发布了72 篇原创文章 · 获赞 89 · 访问量 6534

猜你喜欢

转载自blog.csdn.net/scfor333/article/details/104550673
今日推荐