第五章算法作业-回溯法

一、对回溯法的理解

  回溯法相当于就是从一个全排列中找到那个最优解,但又不仅仅是全排列遍历,在问题的解空间树中,按照深度优先搜索,从根节点开始往下遍历,中间经过约束函数和限界函数剪枝,减少遍历次数,如果不满足向下遍历的条件,就会上上回溯遍历解空间树,否则就继续向下按照深度优先搜索最优解。

二、子集和问题

  

   解空间是(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 }

三、学习中的问题和结队编程问题

  我觉得学习回溯法的时候最难得就是约束函数和限界函数的选择,而且这两个真的有点难,这两个函数一旦没做好,就会导致算法超时,也会导致最终结果错误。

  我们结队编程没遇到很难的问题,我队友对约束函数这一块理解的比较好,总是在编程的时候帮助我,就很好。

猜你喜欢

转载自www.cnblogs.com/jewfer-03-08/p/12060830.html