算法第五章作业

1.你对回溯算法的理解(2分)

基本概念:回溯法是一个类似枚举搜索的过程,在这个过程中找到解,如果在搜索到一的结点的时候不满足题目要求,就回溯到上一个结点,再搜索别的路径是否为最优解。

特点:采用深度优先的搜索方法,若需要求问题的所有解,则回溯到根结点,若只需求一个解,则只需搜索到一个点即可结束。

解题步骤:首先确定问题的解空间,问题的解空间应至少包含问题的一个(最优)解;再确定结点的扩展搜索规则,子集数or排列树;以深度优先方式搜索解空间,并用剪枝函数,使搜索效率更高。

剪枝函数:用约束函数在扩展结点处剪去不满足约束的子树;和用限界函数剪去得不到最优解的子树。

2.请说明“子集和”问题的解空间结构和约束函数(2分)

7-1 子集和问题 (50 分)

设集合S={x1,x2,…,xn}是一个正整数集合,c是一个正整数,子集和问题判定是否存在S的一个子集S1,使S1中的元素之和为c。试设计一个解子集和问题的回溯法。

输入格式:

输入数据第1行有2个正整数n和c,n表示S的大小,c是子集和的目标值。接下来的1行中,有n个正整数,表示集合S中的元素。 是子集和的目标值。接下来的1 行中,有n个正整数,表示集合S中的元素。

输出格式:

输出子集和问题的解,以空格分隔,最后一个输出的后面有空格。当问题无解时,输出“No Solution!”。

输入样例:

在这里给出一组输入。例如:

5 10
2 2 6 5 4

输出样例:

在这里给出相应的输出。例如:

2 2 6 
 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 int n, c, flag = 1;
 5 int a[10005], choice[10005], record[10005],sum = 0;
 6 void Backtrack(int t) {
 7     if (!flag) 
 8         return;
 9     else {
10         for (int i = t; i < n; i ++ ) {
11             if (!choice[i] && (c - a[i]) >= 0) {
12                 c -= a[i];
13                 choice[i] = 1;
14                 record[i] = a[i];
15                 if (c == 0) {
16                     for(int t = 0; t < 10005; t ++ ) {
17                         if(record[t]!=0)
18                             cout << record[t] << ' ';
19                     }
20                     cout << endl;
21                     flag = 0;
22                     return;
23                 }
24                 else {
25                     Backtrack(t+1);
26                     if (!flag) return;
27                     c += a[i];
28                     choice[i] = 0;
29                     record[i] = 0;
30                 }
31             }
32         }
33     }
34 }
35 int main() {
36     cin >> n >> c;
37     for (int i = 0; i < n; i ++ ) {
38         cin >>a[i];
39         sum += a[i];
40     }
41     if (sum < c) {
42         cout << "No Solution!" << endl;
43         return 0;
44     }
45     memset(choice, 0, sizeof(choice));
46     memset(record, 0, sizeof(record));
47     Backtrack(0);
48     if (flag)
49         cout << "No Solution!" << endl;
50     return 0;
51 } 
/*从第一个元素开始,如果此时当前的元素不在集合内的话
将这个元素加到子集当中来(用record数组标记) ,将sum加上这个元素的值。
然后判断如果sum恰好为目标值c的话,就返回正值并且打印结果。
如果sum > c 的话则舍弃当前这个元素,修改标记数组,并且将sum减去这个元素的值。
只要还有元素没有判断就继续选择。直到第n个元素,如果第n个元素判断完还没有找到解的话,
就回溯到上一次选择的那个点,将其从集合里面删除并从它后一个点继续重复前面的操作。*/

解空间结构:子集树的解空间的个数是指数级别的,为2^n

剪枝函数:如果回溯的时候回溯到了第一个元素之前,则要么所有元素都加入到集合都不够,或者是所有的情况都找过了还是没有解决方案,这个时候返回无解,这部分将被舍弃,回溯寻找其他路径。 

3.请说明在本章学习过程中遇到的问题及结对编程的情况(1分)

当我逐步了解回溯法的框架和含义后,题目也更好理解了。我的队友总是非常耐心地向我讲解,帮助我对回溯法了解得更透彻了。

posted @ 2018-12-19 21:51  imweili  阅读(360)  评论(0编辑  收藏  举报