回溯与搜索 一 全排列问题

简介: 回溯与搜索 一 全排列问题

     回溯是搜索算法中的一种控制策略。它的基本思想是:为了求得问题的解,先选择某一种可能情况向前探索,在探索过程中,一旦发现原来的选择是错误的,就退回一步重新选择,继续向前探索,如此反复进行,直至得到解或证明无解。

      如迷宫问题:进入迷宫后,先随意选择一个前进方向,一步步向前试探前进,如果碰到死胡同,说明前进方向已无路可走,这时,首先看其它方向是否还有路可走,如果有路可走,则沿该方向再向前试探;如果已无路可走,则返回一步,再看其它方向是否还有路可走;如果有路可走,则沿该方向再向前试探。按此原则不断搜索回溯再搜索,直到找到新的出路或从原路返回入口处无解为止。

1. //递归回溯算法框架 一 
2. void search(int k)
3. {
4.  for(i=1;i<=算符种数;i++)
5.    if(满足条件)
6.    {
7.      保存结果;
8.      if(到目的地)输出解;
9.      else search(k+1);
10.       恢复 保存结果之前的状态{回溯一步;} 
11.      } 
12. }
13. //递归回溯算法框架 二
14. void search(int k)
15. {
16.   if(到目的地)输出解;
17.   else
18.     for(i=1;i<=算符种数;i++)
19.       if(满足条件)
20.       {
21.         保存结果;
22.         search(k+1);
23.         恢复 保存结果之前的状态{回溯一步;} 
24.       }
25.  }

【例1】素数环:从1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数。

【算法分析】 非常明显,这是一道回溯的题目。从1开始,每个空位有20种可能,只要填进去的数合法:与前面的数不相同;与左边相邻的数的和是一个素数。第20个数还要判断和第1个数的和是否素数。

【算法流程】 1、数据初始化;2、递归填数:判断第i个数填入是否合法; A、如果合法:填数;判断是否到达目标(20个已填完):是,打印结果;不是,递归填下一个; B、如果不合法:选择下一种可能;

1~20 组合太多   这里改成了1~6:

1. #include<iostream>
2. #include<cstdio>
3. #include<cmath>
4. using namespace std;
5. int a[7]={0};
6. int b[7]={0}; 
7. int t=0;
8. bool check(int x,int y)//判断素数 
9. {
10.   int z=x+y;
11.   int k=2;
12.   while((z%k!=0)&&(k<=sqrt(z))) k++;
13.   if(k>sqrt(z)) return true;
14.   else return false;
15.  } 
16. void print()//输出及统计 
17.  {
18.   t++;
19.   cout<<t<<"-> "; 
20.   for(int j=1;j<6;j++) cout<<a[j]<<" ";
21.   cout<<a[6]<<endl; 
22.  }
23. void search(int n)
24.  {
25.   for(int i=1;i<=6;i++)//由1-6 个可选数 
26.       //与前一个数构成素数 且未使用过 
27.     if(check(a[n-1],i)&&(b[i]==0)) 
28.     {
29.       a[n]=i;
30.       b[i]=1;
31.       //是最后一个数 且与第一个数构成素数 
32.       if(n==6&&check(a[6],a[1])) print();  
33.       search(n+1);//调用下一个 
34.       b[i]=0; //取消使用标记 
35.      }
36.  }
37. int main()
38. {
39.   search(1);
40.   cout<<t;
41.   return 0;
42. }

【例2】设有n个整数的集合{1,2,…,n},从中取出任意r个数进行排列(r<n),试列出所有的排列。

1. #include<iostream>
2. #include<cstdio>
3. #include<cmath>
4. using namespace std;
5. int n,r,t=0;
6. int a[101]={0},b[101]={0};
7. void search(int m)
8. {
9.  for(int i=1;i<=n;i++){
10.     if(b[i]==0){
11.       b[i]=1;
12.       a[m]=i;
13.       if(m==r){
14.         for(int j=1;j<r;j++) cout<<a[j]<<" ";
15.         cout<<a[r]<<endl;
16.         t++;
17.       }
18.       search(m+1);
19.       b[i]=0;
20.     }
21.   }
22. }
23. int main()
24. {
25.   cin>>n>>r;
26.   search(1);
27.   cout<<t<<endl;
28.   return 0;
29. }

【例3】任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。

当n=7共14种拆分方法:

7=1+1+1+1+1+1+1

7=1+1+1+1+1+2

7=1+1+1+1+3

7=1+1+1+2+2

7=1+1+1+4

7=1+1+2+3

7=1+1+5

7=1+2+2+2

7=1+2+4

7=1+3+3

7=1+6

7=2+2+3

7=2+5

7=3+4

total=14

1. #include<iostream>
2. #include<cstdio>
3. #include<cmath>
4. using namespace std;
5. int s[101]={1};
6. int n,sum=0;
7. void print(int m)
8. {
9.  cout<<n<<"=";
10.   for(int j=1;j<m;j++) cout<<s[j]<<"+";
11.   cout<<s[m]<<endl;
12.   sum++;
13. }
14. void search(int a,int m)
15. {
16.   int i;
17.   for(i=s[m-1];i<=a;i++){
18.     if(i<n){
19.       s[m]=i;
20.       a-=i;
21.       if(a==0) print(m);
22.       else search(a,m+1);
23.       a+=i;
24.     }
25.   }
26. }
27. int main()
28. {
29.   cin>>n;
30.   search(n,1);
31.   cout<<"total="<<sum; 
32.   return 0;
33. }


相关文章
|
1月前
|
算法
【递归搜索回溯专栏】专题一递归:快速幂
【递归搜索回溯专栏】专题一递归:快速幂
27 0
|
1月前
|
算法
【算法系列篇】递归、搜索和回溯(四)
【算法系列篇】递归、搜索和回溯(四)
|
1月前
|
算法 前端开发 搜索推荐
二分查找算法:搜索有序数组中目标元素的利器
二分查找算法:搜索有序数组中目标元素的利器
|
1月前
|
算法
【算法系列篇】递归、搜索和回溯(二)
【算法系列篇】递归、搜索和回溯(二)
|
1月前
|
算法
【算法系列篇】递归、搜索与回溯(一)
【算法系列篇】递归、搜索与回溯(一)
|
1月前
|
算法
【算法系列篇】递归、搜索和回溯(三)
【算法系列篇】递归、搜索和回溯(三)
|
11月前
|
人工智能 算法 安全
回溯与搜索 二 八皇后问题 马的遍历
回溯与搜索 二 八皇后问题 马的遍历
|
11月前
回溯与搜索 四 跳马问题
回溯与搜索 四 跳马问题
|
算法
每日一题——搜索插入位置(二分查找)
每日一题——搜索插入位置(二分查找)
|
存储 索引
二分查找问题(关键:确定搜索区间)
二分查找问题(关键:确定搜索区间)