理解回溯法及例题分析
Posted cyuchun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解回溯法及例题分析相关的知识,希望对你有一定的参考价值。
1、对回溯算法的理解
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为"回溯点"。
(1)回溯法解题时通常包含3个步骤:
①针对所给问题,定义问题的解空间;
② 确定易于搜索的解空间结构;
③以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
(2)回溯法的算法框架
①解空间:问题的解空间至少包含问题的一个(最优)解。其表示形式一般是解空间树:子集树和排列树
②递归回溯:
1 void Backtrack(int t) 2 { 3 if(t>n) Output(x); 4 else { 5 for(int i=f(n,t);i<=g(n,t);i++) { 6 x[t]=h(i); 7 if(Constraint(t)&&Bound(t)) Backtrack(t+1); 8 } 9 } 10 }
③迭代回溯:
1 void IterativeBacktrack(void) 2 { 3 int t=1; 4 while(t>0) { 5 if(f(n,t)<=g(n,t)) { 6 for(int i=f(n,t);i<=g(n,t);i++) { 7 x[t]=h(i); 8 if(Constraint(t)&&Bound(t)) { 9 if(Solution(t)) Output(x); 10 else t++; 11 } 12 } 13 } 14 else t--; 15 } 16 }
2、例题:子集和问题
(1)子集和问题
设集合S={x1,x2,…,xn}是一个正整数集合,c是一个正整数,子集和问题判定是否存在S的一个子集S1,使S1中的元素之和为c。试设计一个解子集和问题的回溯法。
输入格式:输入数据第1行有2个正整数n和c,n表示S的大小,c是子集和的目标值。接下来的1行中,有n个正整数,表示集合S中的元素。
输出格式:输出子集和问题的解,以空格分隔,最后一个输出的后面有空格。当问题无解时,输出“No Solution!”。
输入样例:5 10
2 2 6 5 4
输出样例:2 2 6
(2)解空间
本题的解空间为:{x1,x2,x3,x4,···,xn},其中xi表示是否加上第i个数
(3)约束函数
本题的约束方式有两部分,①isC + num[i] <= c,通过判断当前子集和是否超出题目要求的子集和来剪枝
②isC+total >= c,与第一部分类似
(4)具体代码
1 #include <iostream> 2 using namespace std; 3 #define N 1000 4 int n,c,total=0; // total表示所有整数之和 5 int isSelect[N]={0}; // 表示整数n是否被选择,1表示选择 6 int num[N]; // 表示整数集 7 int isC=0; // 表示当前子集和 8 9 bool sum(int i) 10 { 11 if(isC == c) return true; // 当子集和符合条件时返回 12 if(i > n) return false; 13 total-=num[i]; 14 if(isC + num[i] <= c) { 15 isSelect[i]=1; 16 isC+=num[i]; 17 if(sum(i+1)) return true; 18 isC-=num[i]; // 回溯法 19 } 20 if(isC+total >= c) { 21 isSelect[i]=0; // 回溯法 22 if(sum(i+1)) return true; 23 } 24 total += num[i]; // 回溯法 25 return false; 26 } 27 28 int main() 29 { 30 cin>>n>>c; 31 for(int i=1;i<=n;i++) { 32 cin>>num[i]; 33 total+=num[i]; 34 } 35 if(!sum(1)) cout<<"No Solution!"; // 无解时 36 else { 37 for(int i=1;i<=n;i++) { 38 if(isSelect[i]) cout<<num[i]<<" "; 39 } 40 } 41 return 0; 42 }
3、在本章学习过程中遇到的问题及结对编程的情况
对于回溯法的概念,结合解空间树,理解起来不是很难,但是在代码实践时,有时候会出现不是很明白为什么要怎么写代码的情况,结对小伙伴也不是很明白,总体上还可以,但是还需要多实践多理解。
参考资料:https://baike.so.com/doc/6735197-6949574.html
以上是关于理解回溯法及例题分析的主要内容,如果未能解决你的问题,请参考以下文章