您的位置:首页 > 财经 > 金融 > seo外包服务价格_深圳做人工智能芯片的公司_百度官方营销推广平台_互联网营销专家

seo外包服务价格_深圳做人工智能芯片的公司_百度官方营销推广平台_互联网营销专家

2025/3/17 8:13:54 来源:https://blog.csdn.net/2302_80871796/article/details/146303185  浏览:    关键词:seo外包服务价格_深圳做人工智能芯片的公司_百度官方营销推广平台_互联网营销专家
seo外包服务价格_深圳做人工智能芯片的公司_百度官方营销推广平台_互联网营销专家

        深度优先搜索(DFS)剪枝技术通过提前终止无效路径的搜索,大幅提升算法效率。以下是五种核心剪枝技术的详细解析及C++代码示例:

目录

一、可行性剪枝

C++实现示例

二、搜索顺序剪枝

伪代码逻辑

三、最优性剪枝

C++实现示例

四、排除等效冗余

C++实现示例

五、记忆化搜索(Memoization)

C++实现示例

六、总结

七、 小例题

P1025 [NOIP 2001 提高组] 数的划分 - 洛谷

算法代码: 

代码设计思路详解

为什么这样设计?


一、可行性剪枝

核心思想:若当前路径明显无法满足问题的约束条件,则提前回溯。
典型应用:组合总和问题。

C++实现示例

class Solution {
public:vector<vector<int>> combinationSum(vector<int>& candidates, int target) {vector<vector<int>> res;vector<int> path;sort(candidates.begin(), candidates.end()); // 排序便于剪枝dfs(candidates, target, 0, path, res);return res;}void dfs(vector<int>& nums, int target, int start, vector<int>& path, vector<vector<int>>& res) {if (target < 0) return; // 可行性剪枝:路径和已超目标if (target == 0) {res.push_back(path);return;}for (int i = start; i < nums.size(); ++i) {if (nums[i] > target) break; // 剪枝:后续元素更大,无需尝试path.push_back(nums[i]);dfs(nums, target - nums[i], i, path, res); // 允许重复path.pop_back();}}
};

二、搜索顺序剪枝

核心思想:调整搜索顺序,优先处理更可能找到解的分支,减少无效搜索。
典型应用:数独问题中优先填充空格较少的行或列。

伪代码逻辑

void solveSudoku(vector<vector<char>>& board) {vector<pair<int, int>> emptyCells = findEmptyCells(board);sort(emptyCells.begin(), emptyCells.end(), [&](auto& a, auto& b) {return getCandidates(a).size() < getCandidates(b).size(); // 优先候选少的格子});dfs(board, emptyCells, 0);
}

三、最优性剪枝

核心思想:若当前路径的代价已超过已知最优解,则停止搜索。
典型应用:旅行商问题(TSP)的简化版本。

C++实现示例

int minCost = INT_MAX;void dfs(int current, int cost, int visited, vector<vector<int>>& graph) {if (cost >= minCost) return; // 最优性剪枝:当前路径已不如已知最优if (visited所有节点) {minCost = min(minCost, cost);return;}for (int next = 0; next < graph.size(); ++next) {if (!visited[next]) {dfs(next, cost + graph[current][next], visited | (1 << next), graph);}}
}

四、排除等效冗余

核心思想:跳过重复或等效的状态,避免生成相同结果的多个分支。
典型应用:含重复元素的全排列问题。

C++实现示例

class Solution {
public:vector<vector<int>> permuteUnique(vector<int>& nums) {vector<vector<int>> res;vector<int> path;vector<bool> used(nums.size(), false);sort(nums.begin(), nums.end()); // 排序便于去重dfs(nums, used, path, res);return res;}void dfs(vector<int>& nums, vector<bool>& used, vector<int>& path, vector<vector<int>>& res) {if (path.size() == nums.size()) {res.push_back(path);return;}for (int i = 0; i < nums.size(); ++i) {if (used[i] || (i > 0 && nums[i] == nums[i-1] && !used[i-1])) continue; // 剪枝:避免重复排列used[i] = true;path.push_back(nums[i]);dfs(nums, used, path, res);path.pop_back();used[i] = false;}}
};

五、记忆化搜索(Memoization)

核心思想:缓存已计算的状态结果,避免重复递归调用。
典型应用:斐波那契数列、爬楼梯问题。

C++实现示例

unordered_map<int, int> memo;int fib(int n) {if (n <= 1) return n;if (memo.find(n) != memo.end()) return memo[n]; // 直接返回缓存结果memo[n] = fib(n-1) + fib(n-2);return memo[n];
}

六、总结

  • 可行性剪枝:提前终止不可能满足约束的路径。

  • 搜索顺序剪枝:优化搜索顺序以快速逼近解。

  • 最优性剪枝:维护已知最优解,剪掉更劣路径。

  • 排除等效冗余:避免重复状态,减少冗余计算。

  • 记忆化搜索:缓存中间结果,避免重复递归。

综合应用:在实际问题中,常需结合多种剪枝技术。例如:

  1. 预处理排序(可行性剪枝 + 排除等效冗余)。

  2. 状态记录(记忆化搜索 + 排除等效冗余)。

  3. 动态更新最优解(最优性剪枝 + 可行性剪枝)。


七、 小例题

P1025 [NOIP 2001 提高组] 数的划分 - 洛谷

        整数划分是经典问题,标准解法是动态规划、母函数,计算复杂度为O(n^2)。当n较小时,也可以用DFS暴搜出答案。

算法代码: 

#include <bits/stdc++.h>  // 包含标准库的所有头文件
using namespace std;  // 使用标准命名空间int n, k, cnt;  // n: 要划分的整数;k: 划分的份数;cnt: 记录合法的划分方案数void dfs(int x, int sum, int u) {  // DFS函数,参数为:x: 上次划分的数;sum: 前u-1个数的和;u: 已经划分的数的个数if (u == k) {  // 如果已经划分了k个数if (sum == n) cnt++;  // 如果这些数的和等于n,则cnt加1return;  // 返回,结束当前DFS分支}for (int i = x; sum + i * (k - u) <= n; i++) {  // 从x开始枚举下一个数,确保剩余数的和不超过ndfs(i, sum + i, u + 1);  // 递归调用DFS,继续划分下一个数}
}int main() {cin >> n >> k;  // 输入n和kdfs(1, 0, 0);  // 从1开始划分,初始和为0,已划分的数的个数为0cout << cnt;  // 输出合法的划分方案数return 0;  // 程序正常结束
}

代码设计思路详解

  1. 问题分析

    • 题目要求将整数n划分为k份,且每份不能为空,且不考虑顺序。

    • 例如,n=7, k=3时,{1,1,5}、{1,5,1}、{5,1,1}被认为是相同的划分,只算一种。

  2. DFS模拟划分过程

    • 为了避免重复计算,DFS过程中强制要求划分的数从小到大排列。

    • 第一个数从1开始,第二个数必须大于或等于第一个数,以此类推。

    • 这样做的目的是确保划分的唯一性,避免重复计算。

  3. 剪枝优化

    • 在DFS过程中,通过sum + i * (k - u) <= n进行剪枝。

    • 这个条件的意思是:当前划分的数i,加上剩余未划分的数(每个数至少为i),总和不能超过n

    • 如果超过n,则当前分支不可能得到合法的划分,直接跳过。

  4. 递归终止条件

    • 当已经划分了k个数(u == k),并且这些数的和等于nsum == n),则说明找到了一个合法的划分方案,cnt加1。

  5. 时间复杂度

    • 由于DFS需要枚举所有可能的划分方案,当n=200k=6时,计算量非常大(代码中提到num=147123026)。

    • 但由于剪枝的存在,实际计算量会大大减少。

为什么这样设计?

  1. 从小到大划分

    • 为了避免重复计算,强制要求划分的数从小到大排列。

    • 例如,{1,2,4}和{1,4,2}是相同的划分,但通过从小到大排列,只计算{1,2,4}。

  2. 剪枝条件

    • sum + i * (k - u) <= n是核心剪枝条件。

    • 它确保了当前划分的数i加上剩余数的和不会超过n,从而避免了无效的DFS分支。

  3. 递归设计

    • 每次递归调用时,x表示当前划分的数,sum表示前u-1个数的和,u表示已经划分的数的个数。

    • 这种设计使得DFS能够逐步构建划分方案,并在每一步进行剪枝。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com