经典算法学习之回溯法
时间:2022-04-26
本文章向大家介绍经典算法学习之回溯法,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
回溯法的应用范围:只要能把待求解的问题分成不太多的步骤,每个步骤又只有不太多的选择就可以考虑使用回溯法。
若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
回溯法将问题的候选解按照某一顺序逐一枚举和检验。当发现当前候选解不可能是解时,就选择下一个候选解,若当前候选解符合要求,且还未达到求解的规模,则继续扩展当前候
选解的规模,如果候选解已经满足了所有要求,并且也达到了问题的规模,那么该候选解就是问题的一个解。
例、在9(3*3)的方格内填入1到N(N>=10)内的某9个数字,每个方格填入一个数字,使方格内所有相邻的两个数的和为质数,试求出满足要求的所有填法。
伪代码:
1 int m=0; //已经填入m个数
2 bool ok=true;//ture表示已经填入的前m个数都符合要求
3 int n=8; //填入最后一个数字的下标
4 do
5 {
6 if(ok)
7 {
8 if(m==n)
9 {
10 print();//输出这个解
11 change();//调整最后一个值,找下一个解
12 }
13 else
14 {
15 extend();//往下一个空的方格中填入数字
16 }
17 }
18 else
19 {
20 change();//调整最近填入的一个值
21 }
22 ok=检查前m个数是否都符合要求;
23 }while(m>=0)//由于是求解所有解,所以必须回溯到根的所有情况才算结束
程序如下:
1 #include<iostream>
2 #include<math.h>
3 using namespace std;
4 const int N=12;
5 int a[10];//记录符合条件的数
6 bool b[N+1];//记录某个数是否已经被用过true,被用过,false,没被用过
7 int checkmatrix[][3]={{-1},{0,-1},{1,-1},
8 {0,-1},{3,1,-1},{4,2,-1},
9 {3,-1},{6,4,-1},{7,5,-1}};//checkmatirx用来验证相邻的两个数的和是否为指数用的,-1是人为添加的截止符号
10 int m;//已经符合条件的个数
11 void print(int * a)
12 {
13 for(int i=0;i<3;i++)
14 {
15 for(int j=0;j<3;j++)
16 {
17 cout<<a[i+j*3]<<" ";
18 }
19 cout<<endl;
20 }
21 }
22 bool isprime(int m)
23 {
24 if(1==m)
25 {
26 return false;
27 }
28 if(2==m)
29 {
30 return true;
31 }
32 int n=sqrt((float)m);
33 for(int i=2;i<=n;i++)
34 {
35 if(m%i==0)
36 {
37 return false;
38 }
39 }
40 return true;
41 }
42 //返回从start开始的第一个没被用过的数
43 int select(int start)
44 {
45 for(int i=start;i<=N;i++)
46 {
47 if(b[i]==false)
48 {
49 return i;
50 }
51 }
52 return 0;//如果全都被使用过了就返回0
53 }
54 int extend(int m)
55 {
56 a[++m]=select(1);
57 b[a[m]]=true;
58 return m;
59 }
60 int change(int m)
61 {
62 int pos;
63 while(m>=0 && (pos=select(a[m]+1))==0)
64 {
65 b[a[m--]]=false;
66 }
67 if(m<0)
68 {
69 return -1;
70 }
71 else
72 {
73 b[a[m]]=false;
74 a[m]=pos;
75 b[a[m]]=true;
76 }
77 return m;
78 }
79 bool check(int m)
80 {
81 int j;
82 if(m<0)
83 {
84 return false;
85 }
86 int k=m;
87 while(k>=0)
88 {
89 for(int i=0;(j=checkmatrix[k][i])>=0;i++)
90 {
91 if(!isprime(a[k]+j))
92 {
93 return false;
94 }
95 }
96 k--;
97 }
98
99 return true;
100 }
101 int main()
102 {
103 //先全都初始化为未使用过
104 for(int i=0;i<N+1;i++)
105 {
106 b[i]=false;
107 }
108 m=0;
109 a[m]=1;
110 b[a[m]]=true;
111 bool ok=true;//前m个数都满足条件的话ok为true否则为false
112 do
113 {
114 if(ok)
115 {
116 if(8==m)
117 {
118 print(a);
119 //调整
120 m=change(m);
121
122 }
123 else
124 {
125 //扩展
126 m=extend(m);
127 }
128 }
129 else
130 {
131 //调整
132 m=change(m);
133 }
134 //检查前m个数是否都满足条件
135 ok=check(m);
136 }while(m>=0);
137
138 return 0;
139 }
如果将题目改成找出一种填法,则不需要回溯到根,而是找到一个解就可以结束了 伪代码如下:
1 int m=0;
2 bool ok=true;
3 int n=8;
4 do
5 {
6 if(ok)
7 {
8 extend()//扩展解
9 }
10 else
11 {
12 change();//调整最近填入的数字
13 }
14 ok=检查填入的m个数的合理性;
15 }while((m!=n||!ok)&&m!=0)
16 if(m==n)
17 {
18 print();//输出解
19 }
20 else
21 {
22 无解;
23 }
- 使用ControllerAdvice注意事项,Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.
- rac节点无法启动ORA-29702的问题及分析(70天)
- SpringMVC,SpringBoot文件下载
- SpringCloud学习1-服务注册与发现(Eureka)
- 物化视图全量刷新与insert的redo生成量测试(69天)
- SpringCloud学习2-Springboot监控模块(actuator)
- 原码,反码,补码 与(&) 或(|) 非(~) 异或(^) 左移 << 右移 >> 无符号右移 >>>
- lombok使用基础教程
- 【Android基础】Android中的Intent详解
- 关于SCN的总结测试 (68天)
- 利用主成分分析构建股票指数
- Java对象的序列化和反序列化源码阅读
- hexo 博客支持PWA和压缩博文
- Hexo next博客添加折叠块功能添加折叠代码块
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【DB笔试面试855】在Oracle中,简单说说PSU升级的过程
- HashMap中add()方法的源码学习
- IOC容器实现
- Docker安装mysql
- 【LeeCode 面试题】二叉树的前序遍历,中序遍历,后序遍历递归和迭代的两种实现方式
- MySQL笔记汇总
- 【DB笔试面试856】在Oracle中,如何判定实例是否运行?
- 【DB笔试面试857】在Oracle中,若一个主机上有多个Oracle实例,则如何确定哪些共享内存段属于想要清掉的实例的内存段?
- vue + flask实现邮件密码找回功能
- PicGo + Gitee 构建免费云图床
- python scipy.stats计算单样本假设检验(1 sample test)
- python scipy.stats计算双独立样本假设检验(2 sample independent test)
- 深入理解JS的事件循环
- C语言必背的18个经典程序。
- 打卡群刷题总结0811——从中序与后序遍历序列构造二叉树