回溯经典例题

回溯基本思路

问题解析
解决回溯问题,实际上就是一个决策树的遍历过程
其核心就是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分类里,有兴趣的小伙伴可以去看一看!

posted @ 2022-01-12 17:33  scannerkk  阅读(123)  评论(0)    收藏  举报