一、对回溯法的理解
回溯法相当于就是从一个全排列中找到那个最优解,但又不仅仅是全排列遍历,在问题的解空间树中,按照深度优先搜索,从根节点开始往下遍历,中间经过约束函数和限界函数剪枝,减少遍历次数,如果不满足向下遍历的条件,就会上上回溯遍历解空间树,否则就继续向下按照深度优先搜索最优解。
二、子集和问题
解空间是(1, 1, 1, 0, 0),这是用向量表示,1代表选择这个数,0代表不选择。
约束函数:sum + s[t] <= c。t是当前要遍历的结点,sum是当前子集和,s[t]是当前结点的数值。
代码如下:
1 #include <iostream> 2 using namespace std; 3 #define MAX 1000 4 5 int n; // 集合大小 6 int c; // 目标值 7 int s[MAX]; // 集合 8 int sum = 0; // 当前和 9 int x[MAX] = { 0 }; // 记录子集 10 int flag = 0; // 记录是否找到可行解 11 12 void backtrack(int t) { 13 if (flag == 1) return; // 找到一个解就返回 14 if (t > n) { 15 // 记录或输出可行解 16 if (sum == c && !flag) { 17 flag = 1; 18 for (int i = 1; i <= n; i++) 19 if (x[i] == 1) 20 cout << s[i] << " "; 21 cout << '\n'; 22 return; 23 } 24 } 25 else { 26 if (sum + s[t] <= c) { 27 x[t] = 1; 28 sum += s[t]; 29 backtrack(t + 1); // 遍历左子树 30 sum -= s[t]; 31 x[t] = 0; 32 } 33 backtrack(t + 1); // 遍历右子树 34 } 35 } 36 37 int main() { 38 cin >> n >> c; 39 int a = 0; 40 for (int i = 1; i <= n; i++) { 41 cin >> s[i]; 42 a += s[i]; 43 } 44 if (a < c) // 如果集合所有元素和都小于目标值,则肯定无解 45 cout << "No Solution!\n"; 46 else { 47 backtrack(1); 48 if (flag != 1) // 回溯后依旧未找到解 49 cout << "No Solution!" << '\n'; 50 } 51 system("pause"); 52 return 0; 53 }
三、学习中的问题和结队编程问题
我觉得学习回溯法的时候最难得就是约束函数和限界函数的选择,而且这两个真的有点难,这两个函数一旦没做好,就会导致算法超时,也会导致最终结果错误。
我们结队编程没遇到很难的问题,我队友对约束函数这一块理解的比较好,总是在编程的时候帮助我,就很好。