DFS深度优先搜索与回溯算法

文章介绍了递归遍历、前序DFS(暴力解法,可能导致超时)和后序DFS(自底向上搜索,通过记忆法优化并剪枝)在解决三角形路径问题中的应用。重点讨论了递归函数参数、返回值、终止条件以及优化策略。

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

目录

递归遍历的三步骤:

DFS/回溯模板 

 练习

1.三角形路径和最大搜索

 (一)前序DFS(从上至下搜索,实际是暴力解法,测试超时)

(二)后序DFS(自底向上搜索,设置memory数组记录各节点子树的最大路径和,相同子树剪枝优化,AC)

(1)递归无返回值

(2)递归有返回值


         DFS是一种遍历/搜索树和图的算法,感觉和回溯算法类似,思想都是沿着树的深度进行(按照前序/中序/后序)递归搜索,直至搜索到某一路径的叶节点(或满足某终止条件),后沿深度进行回溯,搜索其余路径。访问完所有可能路径后,返回目标任务最优解或所有满足条件的路径。

        这实际就是一种暴力解法,时间复杂度高,为了提高算法效率,可分析题目,结合记忆法等对树进行剪枝优化

递归遍历的三步骤:

1.递归函数的参数、返回值(每层递归需要处理的数据)

2.递归终止条件(终止条件错误总会导致操纵系统的内存栈溢出错误)

3.单层递归逻辑(每层递归需要执行的操作)

DFS/回溯模板 

void dfs(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本节点所连接的其他节点) {
        处理节点;
        dfs(图,选择的节点); // 递归
        回溯,撤销处理结果
    }
}

 练习

1.三角形路径和最大搜索

 (一)前序DFS(从上至下搜索,实际是暴力解法,测试超时)

#include<iostream>
#include<vector>
using namespace std;
 
void output(vector<vector<int>>& input){
    for(int i=0; i<input.size(); i++){
        for(auto it=input[i].begin(); it!= input[i].end(); it++){
            cout<<*it<<" ";
        }
        cout<<endl;
    }
}
 
struct TreeNode{
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode* left, TreeNode* right) : val(x), left(left), right(right) {}
};
 
class solution
{
private:
    int maxSum;
    // 前序深度遍历
    void traversal(vector<vector<int>>& tree, int depth, int width, int sum){
        //
        if(depth >= tree.size()){
            if(sum > maxSum) maxSum = sum;
            return;
        }
        // mid
        sum += tree[depth][width];
        // left
        traversal(tree, depth+1, width, sum);
        // right
        traversal(tree, depth+1, width+1, sum);
    }
public:
    int getMaxPathSum(vector<vector<int>>& input_tree){
        maxSum = -1;
        traversal(input_tree, 0, 0, 0);
        return maxSum;
    }
};
 
int main()
{
    // input;
    int num;
    cin>>num;
    while(num--){
        vector<vector<int>> input_tree;
        int depth;
        cin>>depth;
        for(int i=1; i<=depth; i++){
            vector<int> tmp;
            int input;
            for(int j=0; j<i; j++){
                cin>>input;
                tmp.push_back(input);
            }
            input_tree.push_back(tmp);
        }
         
        // // debug_input
        // output(input_tree);
         
        solution mySolve;
        int res = mySolve.getMaxPathSum(input_tree);
        cout<<res<<endl;
    }
    return 0;
}

(二)后序DFS(自底向上搜索,设置memory数组记录各节点子树的最大路径和,相同子树剪枝优化,AC)

(1)递归无返回值

#include<iostream>
#include<vector>
using namespace std;
 
 
void debug_input(vector<vector<int>>& input){
    for(int i=0; i<input.size(); i++){
        for(auto it=input[i].begin(); it!=input[i].end(); it++){
            cout<<*it<<" ";
        }
        cout<<endl;
    }
}
 
class solution
{
private:
    vector<vector<int>> memory;// 记录每个子树maxSum
    // 从下至上遍历->后序->相同子树剪枝
    void traversal(vector<vector<int>>& input, int depth, int width){
        // 终止条件->遇叶节点
        if(depth == input.size()-1){
            memory[depth][width] = input[depth][width];
            return;
        }
        // 遇相同子树->剪枝
        if(memory[depth][width]) return;
         
        // 后序遍历
        // left
        traversal(input, depth+1, width);
        // right
        traversal(input, depth+1, width+1);
        // mid
        memory[depth][width] = input[depth][width] + max(memory[depth+1][width], memory[depth+1][width+1]);
    }
public:
    int getMaxPathSum(vector<vector<int>>& input){
        vector<int> vec(input.size(), 0);
        memory.resize(input.size(), vec);
        traversal(input, 0, 0);
        return memory[0][0];
    }
};
 
int main()
{
    int num;
    cin>>num;
    while(num--){
        vector<vector<int>> input;
        int depth;
        cin>>depth;
        for(int i=1; i<=depth; i++){
            vector<int> tmp;
            for(int j=0; j<i; j++){
                int in;
                cin>>in;
                tmp.push_back(in);
            }
            input.push_back(tmp);
        }
        // debug_input(input);
         
        solution my_solve;
        int res = my_solve.getMaxPathSum(input);
        cout<<res<<endl;
    }
    return 0;
}

(2)递归有返回值

#include<iostream>
#include<vector>
using namespace std;
 
 
void debug_input(vector<vector<int>>& input){
    for(int i=0; i<input.size(); i++){
        for(auto it=input[i].begin(); it!=input[i].end(); it++){
            cout<<*it<<" ";
        }
        cout<<endl;
    }
}
 
class solution
{
private:
    vector<vector<int>> memory;// 记录每个子树maxSum
    // 从下至上遍历->后序->相同子树剪枝
    int traversal(vector<vector<int>>& input, int depth, int width){
        // 终止条件->遇叶节点
        if(depth >= input.size()-1){
            return input[depth][width];
        }
        // 遇相同子树->剪枝
        if(memory[depth][width]) return memory[depth][width];
         
        // 后序遍历
        // left
        int left_sum = traversal(input, depth+1, width);
        // right
        int right_sum = traversal(input, depth+1, width+1);
        // mid
        memory[depth][width] = input[depth][width] + max(left_sum, right_sum);
        return memory[depth][width];
    }
public:
    int getMaxPathSum(vector<vector<int>>& input){
        vector<int> vec(input.size(), 0);
        memory.resize(input.size(), vec);
        int res = traversal(input, 0, 0);
        return res;
    }
};
 
int main()
{
    int num;
    cin>>num;
    while(num--){
        vector<vector<int>> input;
        int depth;
        cin>>depth;
        for(int i=1; i<=depth; i++){
            vector<int> tmp;
            for(int j=0; j<i; j++){
                int in;
                cin>>in;
                tmp.push_back(in);
            }
            input.push_back(tmp);
        }
        // debug_input(input);
         
        solution my_solve;
        int res = my_solve.getMaxPathSum(input);
        cout<<res<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值