【主要内容】
回顾旧知识 回溯法(子集和,数独)
学习新知识 动态规划(数字三角形,矩阵连乘,石子合并)
子集和
【题目描述】
子集和问题的一个实例为<S,c>。其中S={x1,x2,…,xn}是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得S1中所有元素的和为c。 试设计一个解子集和问题的回溯法。
5 10 2 2 6 5 4
【样例输出】
2 2 6
【题解】
如同回溯法解决01背包问题一样,这里子集和,问题等价为背包容量为10,如下有2,2,6,5,4五个物品,价值和重量都一样 。不过还是利用0代表不取,1代表取其物品。
构建搜索二叉树,每一层都是一个物品,左子树是取,右子树是不取,当走到某一叶子结点时该结点的价值之和为10时,说明有一组解
1 #include<cstdio> 2 3 const int N = 30 ; 4 int vis[N] ; 5 int a[N] ; 6 int n , k ; 7 bool flag = false ; 8 void dfs( int step , int sum ){ 9 if( sum == k ){ 10 for( int i = 1 ; i <= n ; i++ ) 11 if( vis[i] ) printf("%d ",a[i]); 12 putchar('\n'); 13 flag = true ; 14 return ; 15 } 16 if( step == n + 1 ) return ; 17 if( sum + a[step] <= k ){ 18 vis[step] = 1 ; 19 dfs( step + 1 , sum + a[step] ); 20 vis[step] = 0 ; 21 } 22 dfs( step + 1 , sum ); 23 } 24 int main() 25 { 26 scanf("%d%d",&n,&k); 27 for( int i = 1 ; i <= n ; i++ ){ 28 scanf("%d",&a[i]); 29 } 30 dfs( 1 , 0 ); 31 if( !flag ){ 32 printf("-1\n"); 33 } 34 return 0 ; 35 }