回溯法
深度优先策略(回忆深度优先遍历二叉树思路)
解题步骤:
1)针对所给问题,定义问题的解空间;例如,n个物品的0-1背包问题所对应的解空间树是一棵子集树。
2)确定易于搜索的解空间结构;
3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数(****约束函数除去不满足约束的子树,限界函数减去得不到最优解的子树**)**避免无效搜索
## 子集树和递归树
扩展结点:一个正在产生儿子的结点称为扩展结点。
活结点:一个自身已生成但其儿子还没有全部生成的节点称做活结点。
死结点:一个所有儿子已经产生的结点称做死结点。
1.当所给的问题是从n个元素的集合S中找出满足某种性质的子集时,相应的解空间称为子集树。
0-1背包问题
//回溯法遍历子集树
void Traceback(int k)//k为扩展结点在解空间树中所处的层次
{
if (k > n)//n标识问题的规模
output(x);//存放当前解的一维数组
if (constraint(k))//约束条件
{
//相关标识
backtrack(k + 1);
//相关标识的反操作---->从左子树退回,考虑从父节点的角度(场景复原)
}
if (bound(k))//限定函数
{
//相关标识
backtrack(k + 1);
//相关标识的反操作、、、、?
}
//////或者:
// //for (int i=0;i<=1;i++) { //控制分支的数目,此处只有两个分支,0、1分别代表是否装入背包
////x[t] = i;
////if (constraint(t) && bound(t))
// backtrack(t + 1);
//剪枝函数:约束函数+限界函数 ——> 递归
//// }
////
//// ————————————————
//// 版权声明:本文为优快云博主「有梦想的小树」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。
//// 原文链接:https ://blog.youkuaiyun.com/m0_38109046/article/details/84844640
//////}
}
2.当所给问题是确定n个元素满足某种性质的排列时,相应的解空间树称为 排列树
//回溯法遍历排列树
//void backtrack(int t)//扩展结点在解空间树中所处的层次
//{
// if (t > n)//n:规模
// output(x);//存放当前解的一维数组
// else {
// for (int i = t; i <= n; i++)
//一条12345路径,我们从1出发1->2->3->4->5 那我们backtrace(2)的时候会把2和345交换位置,就是为了获得1->3, 1->4, 1->5开头的路径。
// {
// swap(x[t], x[i]); //实现两个位置的交换
// if (constraint(t) && bound(t)) //约束函数与限定函数
// backtrack(t + 1) //递归
// swap(x[t], x[i]); //恢复原状
//全排列Perm算法同样用到该思路//回看前期文章
// }
// }
//}
// ZhuangZaiWenTi!.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。