再总结下回溯法,回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。基本思想:在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。回溯法解题的时候常遇到两种类型的解空间树:子集树(选择问题)与排列树(排列问题)。当所给的问题是从n个元素的集合S中找出满足某种性质的子集时相应的空间就是子集树。当所给的问题是确定n个元素满足某种性质的排列时,相应的解空间树就是排列树。
子集树(选择问题)的一个例子:
#include <iostream> using std::cin; using std::cout; using std::endl; class Partsum { public: int S = 30; int num = 0; int x[7] = { 0 }; int w[7] = { 0,5,10,12,13,15,18 }; //回溯,sum为当前和,k为层数,r为剩余数的和 void Backtrack(int sum, int k, int r) { if (sum + w[k] == S) { num++; cout << num << ":"; cout << "S = "; for (int i = 1; i <= k; i++) { if (x[i] == 1) { cout << w[i] << "+"; } else { continue; } } cout << w[k] << endl; } //到下一层sum小于S,则进入左子树 if (sum + w[k] + w[k + 1] <= S) { x[k] = 1; Backtrack(sum + w[k], k + 1, r - w[k]); } //剪掉当前值,小于S则不可能是右子树了 if (sum + r - w[k] >= S) { x[k] = 0; Backtrack(sum, k + 1, r - w[k]); } } }; int main(int argc, char* argv[]) { Partsum p; p.Backtrack(0, 1, 73); return 0; }
排列数(排列问题)的一个例子:
#include <iostream> using std::cin; using std::cout; using std::endl; class Arranage { public: float A[4] = { 0,1,2 }; void arrage(int k, int m) { int i, temp; if (k == m) { for (i = 0; i <= m; i++) { cout << A[i] << " "; } cout << endl; } else { for (i = k; i <= m; i++) { swap(A[k], A[i]); arrage(k + 1, m); swap(A[i], A[k]); } } } template<class Type> void swap(Type &x, Type &y) { Type temp; temp = x; x = y; y = temp; } }; int main(int argc, char* argv[]) { Arranage arr; arr.arrage(0, 2); return 0; }