DFS剪枝与优化

剪枝,形象得看,就是剪掉搜索树的分⽀,从⽽减⼩搜索树的规模,排除掉搜索树中没有必要的分⽀,优化时间复杂度。

在深度优先遍历中,有⼏种常⻅的剪枝⽅法:

  1. 排除等效冗余
    如果在搜索过程中,通过某⼀个节点往下的若⼲分⽀中,存在最终结果等效的分⽀,那么就只需要搜索其中⼀条分⽀。
  2. 可⾏性剪枝
    如果在搜索过程中,发现有⼀条分⽀是⽆论如何都拿不到最终解,此时就可以放弃这个分⽀,转⽽搜索其它的分⽀。
  3. 最优性剪枝
    在最优化的问题中,如果在搜索过程中,发现某⼀个分⽀已经超过当前已经搜索过的最优解,那么这个分⽀往后的搜索,必定不会拿到最优解。此时应该停⽌搜索,转⽽搜索其它情况。
  4. 优化搜索顺序
    在有些搜索问题中,搜索顺序是不影响最终结果的,此时搜索顺序的不同会影响搜索树的规模。因此,应当先选择⼀个搜索分⽀规模较⼩的搜索顺序,快速拿到⼀个最优解之后,⽤最优性剪枝剪掉别的分⽀。
  5. 记忆化搜索
    记录每⼀个状态的搜索结果,当下⼀次搜索到这个状态时,直接找到之前记录过的搜索结果。记忆化搜索,有时也叫动态规划。

第一第二条在之前的DFS例题中经常出现,这篇主要介绍一下第三条和第四条

1.P1025 [NOIP 2001 提高组] 数的划分


解题思路

当我们填了pos 个坑时,此时总和是sum ,如果后续坑位全部都填上最⼩值都会超过sum 。说明我们之前填的数太⼤了,导致后⾯怎么填都会超过sum ,直接剪掉。

cpp 复制代码
#include<iostream>
using namespace std;
int n, k;
int ret;
int path;

void dfs(int pos, int begin)
{
	if (pos == k)
	{
		if (path == n)
		{
			ret++;
		}
		return;
	}

	//下次进入循环才能判断
	//if ((n - path) < (k - pos) * begin)
	//{
	//	return;
	//}

	for (int i = begin; i <= n; i++)
	{
		//未进入循环就可以判断
		if ((n - path) < (k - pos) *i )
		{
			return;
		}
		path += i;
		dfs(pos + 1, i);
		path -= i;
	}
}

int main()
{
	cin >> n >> k;
	dfs(0, 1);
	cout << ret;
}

注意

• 如果在进⼊递归之前剪枝,我们不会进⼊⾮法的递归函数中;

• 但是如果在进⼊递归之后剪枝,我们就会多进⼊很多不合法的递归函数中。

这里的dfs(0,1)从0开始是因为我们的判断条件在for循环里面,比如

进入dfs(0,3) ,判断时(n - path) < (k - pos) *i ,这里的k-pos应该是3,如果改成(1,1)则会判断错误

1.2P10483 小猫爬山


解题思路

要加入一只小猫时先判断目前已有的车是否可以加上小猫而且不超重,

不行的话再单开一辆车。

• 优化枚举顺序⼀:从⼤到⼩安排每⼀只猫

重量较⼤的猫能够快速把缆⻋填满,较快得到⼀个最⼩值;

通过这个最⼩值,能够提前把分⽀较⼤的情况提前剪掉。

• 优化枚举策略⼆:先考虑把⼩猫放在已有的缆⻋上,然后考虑重新租⼀辆⻋

因为如果反着来,我们会先把缆⻋较⼤的情况枚举出来,这样就起不到剪枝的效果了。

cpp 复制代码
#include<iostream>
#include <algorithm>
using namespace std;
int n, k, cnt,path;
const int N = 20;
int a[N];
int s[N];
int ret = N;

bool cmp(int a, int b)
{
	return a > b;
}


void dfs(int pos)
{
	//最优性剪枝
	if (cnt >= ret) return;

	if (pos > n)
	{
		ret = cnt;
		return;
	}

	   // 策略三:优化搜索顺序 
       // 先安排在已有的⻋辆上
		for(int i =1;i<=cnt;i++)
		{
	        // 策略⼀:可⾏性剪枝 
			if((s[i]+a[pos])>k)continue;

				s[i] += a[pos];
				dfs(pos + 1);
				s[i] -= a[pos];
			
		}

		cnt++;
		s[cnt] = a[pos];
		dfs(pos + 1);
		s[cnt] = 0;
		cnt--;
}

int main()
{
	cin >> n >> k;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	// 策略三:优化搜索顺序 
	sort(a + 1, a + 1 + n, cmp);

	dfs(1);
	cout << ret;
}
相关推荐
chao1898445 小时前
基于 SPEA2 的多目标优化算法 MATLAB 实现
开发语言·算法·matlab
沪漂阿龙5 小时前
AI大模型面试题:支持向量机是什么?间隔最大化、软间隔、核函数、LinearSVC 全面拆解
人工智能·算法·支持向量机
little~钰6 小时前
倍增算法和ST表
算法
知识领航员7 小时前
蘑兔AI音乐深度实测:功能拆解、实测表现与适用场景
java·c语言·c++·人工智能·python·算法·github
薛定e的猫咪7 小时前
因果推理研究方向综述笔记
人工智能·笔记·深度学习·算法
如何原谅奋力过但无声8 小时前
【灵神高频面试题合集06-08】反转链表、快慢指针(环形链表/重排链表)、前后指针(删除链表/链表去重)
数据结构·python·算法·leetcode·链表
平行侠8 小时前
037插入排序 - 整理扑克牌的算法
数据结构·算法
ECT-OS-JiuHuaShan8 小时前
彻底定理化:从量子纠缠到量子代谢
数据库·人工智能·学习·算法·生活·量子计算
爱喝雪碧的可乐9 小时前
2026 腾讯广告算法大赛优秀方案启示:行为条件化多模态自回归生成推荐摘要
算法·数据挖掘·回归·推荐系统·推荐算法