算法第五章作业
一、对回溯算法的理解
1、概念:回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标,当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择。实际上就是穷举法的改进。回溯法可以避免搜索所有可能的解,可用于求解大规模问题。
2、解空间树及其搜索:回溯法中,问题的解空间一般使用解空间树的方式来组织,树的根节点位于第1层,表示搜索的初始状态,依次向下排列。在搜索至树中任一节点时,先判断该节点对应的部分是否是满足约束条件,或者是否超出目标函数的界,也就是判断该节点是否包含问题的最优解。如果肯定不包含,则跳过对该节点为根的子树的搜索,即所谓的剪枝;否则,进入该节点为根的子树,继续按照深度优先策略搜索。
3、在搜索过程中,通常采用剪枝函数避免无效搜索:
用约束条件剪除得不到的可行解的子树;用目标函数剪取得不到的最优解的子树
4、在用回溯法求解问题时,有以下两种典型的解空间树:
(1)子集树:当所有的问题是从n个元素的集合中找出满足某种性质的子集时,解空间树为子集树。
(2)排列树:当所给出问题是确定n个元素满足某种性质的排列时,解空间为排列树。
5、回溯法的优点在于其结构明确,可读性强,易于理解,而且通过对问题的分析可以大大提高运行效率。
二、请说明“子集和”问题的解空间结构和约束函数
解空间结构:“子集和”问题的求解方法与“01-背包”问题相似,针对解空间的每一个解,检测其是否被选择,如果是,则标记为1;如果不是,则标记为0,并且继续搜索。 直到找到求解的子集和,并输出路径。
约束函数:。当前的子集和大于题目要求的子集和时,舍弃当前节点,不再往下搜索;用一个rest变量记录当前元素到最后一个元素的和,如果当前的和加上rest的和大于要求的子集和,则进入右子树。
#include<iostream> using namespace std; #define N 10000 int n, c, rest = 0; int a[N]; int x[N] = {0}; int sum = 0; bool backtrack(int t) { if( sum == c ) return true; if( t > n ) return false ; rest -= a[t]; if(sum + a[t] <= c) { x[t] = 1 ; sum = sum + a[t] ; if ( backtrack(t + 1) ) return true; sum -= a[t]; } if( sum + rest >= c) { x[t] = 0 ; if ( backtrack(t + 1) ) return true; } rest += a[t]; return false; } int main() { cin >> n >> c; for (int i = 1; i <= n; i++) { cin >> a[i]; rest += a[i]; } if (backtrack(1) == false) cout << "No Solution!"; else for( int i = 1; i <= n; i++) if (x[i] == true) cout << a[i] << " "; cout << endl; return 0; }
三、请说明在本章学习过程中遇到的问题及结对编程的情况
我觉得回溯法挺难的,遇到的最大问题就是画出了解空间树但是却不知道如何确定限界函数,对于回溯的过程也不是很理解。这次的上机实践多亏了partner的帮助与指导,她有些题都知道怎么做,但她不会一个人啪啦啪啦就打完它,总是会给我机会打代码,即使这样让我们完成的速度变慢。
浙公网安备 33010602011771号