最小生成树
Prim
基本思路:将点的集合分为C 和 V-C ,分别为访问过的。
Krusal
将每个顶点维护成单顶点连通分量 C(v1),…C(vn)
1. 先将边进行排序
2. 每次加入权值最小的边,如果两个节点在不同的连通分量,则加入,否则丢弃 最好的实现方式是使用并查集,时间复杂度为 O(|E|log|E|) 使用链表,算法复杂度 O(|V|3)
广度优先
思想:逐层访问搜索树中的节点,用到了队列Q。
访问队列Q的第一个节点:
- 如果绑定函数 B(x) 可能存在可行解,则将它的所有孩子节点压入队列Q末尾;
- 如果是可行解,如果是目标节点,则输出x对应的解
- 如果不可能存在可行解,重复操作。
当队列Q为空时,算法结束。
深度优先
思想: 尽可能深的访问树的节点,优先扩展最近访问过的节点,用到了栈S。
访问栈顶S的第一个元素:
- 如果绑定函数 B(x) 可能存在可行解,则将它的所有孩子节点压入栈S;
- 如果是可行解,如果是目标节点,则输出x对应的解
- 如果不可能存在可行解,重复操作。
当栈S为空时,算法结束。
爬山法
定义了隐式约束P(x),可以判断X是否为目标节点,还可以衡量x与目标节点的距离。
在深度优先的策略进行修改,当扩展一个节点X时,如果不是目标节点,则根据隐式函数P()的值从大到小将x的每一个节点压入栈。 局部贪心
访问栈顶S的第一个元素:
- 如果绑定函数 B(x) 可能存在可行解,根据隐式函数P()的值从大到小将x的每一个节点压入栈;
- 如果是可行解,如果是目标节点,则输出x对应的解
- 如果不可能存在可行解,重复操作。
当栈S为空时,算法结束。
最佳优先
思想: 结合了深度优先和广度优先的简单搜索策略,其实也是爬山法由局部扩展到全局。 最佳优先用到了堆管理扩展节点。
访问堆顶Q的第一个元素:
- 如果绑定函数 B(x) 可能存在可行解,根则将所有孩子节点插入堆;
- 如果是可行解,如果是目标节点,则输出x对应的解
- 如果不可能存在可行解,重复操作。
当栈Q为空时,算法结束。
分支界限法
与前面四种策略不同的是,分支界限法可以用于求解优化问题。 特点:利用已经得到的可行解,剪除不能得到优化解的分支
两个要素:
- 产生可行解的策略,可以用前面的深度优先,爬山法,最佳优先。
- 剪除分支的策略: 判断以x为根节点可行解代价是否大于已知可行解的最小代价。绑定函数,具体判断。
应用
代价矩阵: 为了提高分界法的剪枝能力,可以用代价矩阵的变换得到一个所有可行解的代价下界。
行列进行变化: 使得每一行每一列至少存在一个0的元素。最小代价为减去的值。
代价上升: 得到代价矩阵之后,选择一个0元素,对可行解空间进行划分,右子树(不包含0)代价下界增加最大,每个分支的代价矩阵也发生变化。
A*算法
求解最小化或者最大化问题。
g(n) 为搜索树根节点到节点n的精确代价。
h∗(n) 为节点n到目标节点的最小代价。
f∗(n) 为从根节点到目标节点的最小代价。
f(n) 为 f∗(n) 的估计值, f(n)<=f∗(n)
其实A*算法有点类似于最佳优先策略
访问栈顶S的第一个元素:
- 如果绑定函数 B(x) 可能存在可行解,根据总代价值f(x)从小到大将x的每一个节点压入栈;
- 如果是可行解,如果是目标节点,则输出x对应的解
- 如果不可能存在可行解,重复操作。
当栈S为空时,算法结束。
剪枝: 找到的f(n) > 已知可行解的cost