回溯经典例题
回溯基本思路
问题解析
解决回溯问题,实际上就是一个决策树的遍历过程
其核心就是for循环里面的递归,在递归调用之前做选择,在递归调用之后撤销选择
解决思路
1.路径:也就是已经做出的选择
2.选择列表:也就是你当前可以做的选择
3.结束条件:也就是达决策树底层,无法再做选择的条件
回溯三部曲
1.递归函数返回值
2.确立终止条件
3.单层递归逻辑
一、全排列
代码实现:
1 #include <stdio.h> 2 #include <stdlib.h> 3 int *a=NULL,n; 4 int temp[10]={0},b[10]; 5 void fun(int step) 6 { 7 if(step==n) 8 { 9 for(int j=0;j<n;j++) 10 printf("%d",b[j]); 11 printf("\n"); 12 return ; 13 } 14 for(int j=0;j<n;j++) 15 { 16 if(temp[j]==0)//说明本数字还未被使用 17 { 18 b[step]=a[j]; 19 temp[j]=1;//做出选择 20 fun(step+1);//进行递归查找 21 temp[j]=0;//撤销选择 22 } 23 } 24 } 25 int main() 26 { 27 int i; 28 scanf("%d",&n); 29 a=(int *)malloc(sizeof(int )*n); 30 for(i=0;i<n;i++) 31 { 32 scanf("%d",&a[i]); 33 } 34 fun(0); 35 return 0; 36 }
第二种全排列算法:
1 #include "bits/stdc++.h" 2 using namespace std; 3 void dfs(char *arr,int step,int n) 4 { 5 if(step==n) 6 { 7 for(int j=0;j<n;j++) 8 cout << arr[j]; 9 cout << endl; 10 return; 11 } 12 for(int i=step;i<n;i++) 13 { 14 swap(arr[i],arr[step]);//把第1个位置分别和第二个第三个交换,再把剩下的排列好就行了 15 dfs(arr,step+1,n); 16 swap(arr[i],arr[step]); 17 } 18 } 19 int main() 20 { 21 int t; 22 int n; 23 cin >> t; 24 while(t--) 25 { 26 cin >> n; 27 char*arr = new char[n]; 28 for(int j = 0;j < n;j++) 29 cin >> arr[j]; 30 dfs(arr,0,n); 31 cout << endl; 32 } 33 return 0; 34 }
二、组合:
代码实现:
1 #include <stdio.h> 2 #include <stdlib.h> 3 int *a=NULL,n,k; 4 int b[10]; 5 void fun(int step,int start_index) 6 { 7 if(step==k) 8 { 9 for(int j=0;j<k;j++) 10 printf("%d ",b[j]); 11 printf("\n"); 12 return ; 13 } 14 for(int j=start_index;j<n;j++) 15 { 16 b[step]=a[j]; 17 printf("%d,%d\n",step,start_index);//这里必须采用两个变量,应为当第一个打印完成后,应该把后面的作为首个再打印后面的组合 18 fun(step+1,j+1);//进行递归求解 19 // b[step]=0;//回溯置空,此句这个程序可有可无 20 } 21 } 22 int main() 23 { 24 int i; 25 printf("Please input n nums and k nums combination:"); 26 scanf("%d%d",&n,&k); 27 a=(int *)malloc(sizeof(int )*n); 28 for(i=0;i<n;i++) 29 { 30 scanf("%d",&a[i]); 31 } 32 fun(0,0); 33 return 0; 34 }
剪枝优化后的组合:
1 #include <stdio.h> 2 #include <stdlib.h> 3 int *a=NULL,n,k; 4 int b[10]; 5 void fun(int step,int start_index) 6 { 7 if(step==k) 8 { 9 for(int j=0;j<k;j++) 10 printf("%d ",b[j]); 11 printf("\n"); 12 return ; 13 } 14 for(int j=start_index;j<n-(k-step)+1;j++)//循环处进行剪枝优化 k-step表示还要选多少个数 j<n-(k-step) + 1表示是否还能选k-step个数 加1是因为他能取第n-k(最后一个数)个数 15 { 16 b[step]=a[j]; 17 fun(step+1,j+1);//进行递归求解 18 b[step]=0;//回溯置空,此句这个程序可有可无 19 } 20 } 21 int main() 22 { 23 int i; 24 printf("Please input n nums and k nums combination:"); 25 scanf("%d%d",&n,&k); 26 a=(int *)malloc(sizeof(int )*n); 27 for(i=0;i<n;i++) 28 { 29 scanf("%d",&a[i]); 30 } 31 printf("组合为:\n"); 32 fun(0,0); 33 return 0; 34 }
三、找零钱问题:
1 #include <stdio.h> 2 int money[7]={100,50,20,10,5,2,1}; 3 int temp[251]; 4 int dfs(int n,int i,int num) 5 { 6 if(n==0&&num<=100) 7 return 1; 8 if(n<0||i==7) 9 return 0; 10 if(money[i]>n) 11 return dfs(n,i+1,num);//1-200 20100 12 else 13 { 14 if(temp[n]) 15 return dfs(n-money[i],i,num+1)+temp[n];//61671 16 else 17 { 18 return dfs(n,i+1,num)+dfs(n-money[i],i,num+1); 19 temp[n]++; 20 } 21 } 22 23 } 24 int main() 25 { 26 int i=0; 27 int n; 28 while(scanf("%d",&n)!=EOF) 29 { 30 for(i=1;i<=250;i++) 31 temp[i]=0; 32 if(n==0) 33 break; 34 for(i=0;i<7&&money[i]>n;i++); 35 printf("%d\n",dfs(n,i,0)); 36 } 37 return 0; 38 }
四、总结
本次列出了回溯的基本例题排列和组合,其实还有个八皇后问题,我发在了我的Algorithms分类里,有兴趣的小伙伴可以去看一看!
本文来自博客园,作者:{scanner},转载请注明原文链接:{https://home.cnblogs.com/u/scannerkk/}

浙公网安备 33010602011771号