首页 > 编程语言 >搜索与回溯算法笔记

搜索与回溯算法笔记

时间:2023-02-11 09:22:06浏览次数:51  
标签:search 20 int 个数 笔记 算法 回溯

目录

搜索与回溯算法

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

  迷宫问题:

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

递归回溯算法框架1

int search(int k){
    for(i=1;i<=算符种数;i++){
        if(满足条件){
            保存结果;
        	if(到目的地)输出解;
        	else search(k+1);
        //恢复:保存结果之前的状态
            }
    }
}

递归回溯算法框架2

int search(int k){
    if(到目的地)输出解;
    else 
         for(i=1;i<=算符种数;i++){
        if(满足条件){
            保存结果;
        	search(k+1);
        //恢复:保存结果之前的状态
            }
   		 }
}

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

【算法分析】

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

【算法流程】

(1)数据初始化;(2)递归填数:判断第i个数是否合法。

  • 如果合法:填数;判断是否达到目标(20个已填完):是,打印结果;不是递归填下一个。
  • 如果不合法:选择下一种可能。

【参考程序】

//由于20个数的素数环方案太多,该代码以6个数为例(仅两种方案)
#include<bits/stdc++.h>
using namespace std;
bool b[21]={0,1};//判断是否可用
int total=0,a[21]={0,1};//计数、存储数据
int search(int );//回溯过程
int print();//输出方案
bool pd(int ,int );//判断素数
int n=20;
int main(){
	search(2);
	cout<<total<<endl;
	return 0;
}
int search(int t){
	
	int i;
	for(i=2;i<=n;i++){//有20个数可选
		if(pd(a[t-1],i)&&(!b[i])){//判断与前一个数是否构成素数及该数是否可用
			a[t]=i;
			b[i]=1;
			if(t==n){if(pd(a[n],a[1]))print();}
			else search(t+1);
			b[i]=0;
		}
	}
	
}
int print()
{	
	total++;cout<<"<"<<total<<">";
	for(int j=1;j<=n;j++)
		cout<<a[j]<<" ";
	cout<<endl;
	
	
}
bool pd(int x,int y){
	int k=2,i=x+y;
	while(k<sqrt(i)&&i%k!=0)k++;
	if(k>sqrt(i)) return 1;
	else return 0;
}

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

【参考程序】

#include<bits/stdc++.h>
using namespace std;
int num=0,a[10001]={0},n,r;
bool b[10001]={0};
int search(int);
int print();
int main(){
	cout<<"input n,r:";
	cin>>n>>r;
	search(1);
	cout<<"number="<<num<<endl;
	return 0;
}
int search(int k){
	
	int i;
	for(i=1;i<=n;i++){//有20个数可选
		if(!b[i]){//判断与前一个数是否构成素数及该数是否可用
			a[k]=i;
			b[i]=1;
			if(k==r){print();}
			else search(k+1);
			b[i]=0;
		}
	}
	
}
int print()
{	
	num++;
	for(int j=1;j<=r;j++)
		cout<<setw(3)<<a[j];
	cout<<endl;
	
	
}

例5.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

【参考程序】

#include<bits/stdc++.h>
using namespace std;
int a[10001]={1},n,total;
int search(int ,int);//递归回溯算法
int print(int);//输出
int main(){
	cin>>n;
	search(n,1);//将要拆分的n传递给s
	cout<<"total="<<total<<endl;//输出拆分的方案数
	return 0;
}
int search(int s,int t){
	int i;
	for(i=a[t-1];i<=s;i++){
		if(i<n){//当前数i要大于等于前1位数,且不超过n
			a[t]=i;//保存当前拆分的数i
			s-=i;//s减去数i,s的值将继续拆分。
			if(s==0){print(t);}//当s=0时,拆分输出结果
			else search(s,t+1);//当s>0时,继续递归。
			s+=i;//回溯:加上拆分之前的数,以便产生所有可能的拆分。
		}
	}
	
}
int print(int t)
{	
	cout<<n<<"=";
	for(int i=1;i<=t-1;i++)
		cout<<a[i]<<"+";
	cout<<a[t]<<endl;
	total++;
	
}

标签:search,20,int,个数,笔记,算法,回溯
From: https://www.cnblogs.com/mango01/p/17108785.html

相关文章

  • 斯特林数学习笔记
    斯特林数学习笔记注:本篇只为作者自己看懂,方便以后复习。注意:如无特殊说明,以下公式的范围皆为\(n\ge0\)且\(n\)为整数。因为我太菜啦,所以很多东西都只有最浅显的部分......
  • PLC入门笔记5
    定时器指令及其应用定时器指令介绍设备启动预热时间、化学反应时间、电机星三角转换时间?我们需要定时器。PLC计时器指令由时间续电器演变而来。定时器本质是一个输出指......
  • 代码随想录算法训练营第十天【栈与队列】232.用栈实现队列、225.用队列实现栈
    232.用栈实现队列力扣题目链接心得:思路不难,栈和队列的特性要掌握1)栈,先进后出;队列,先进先出2)初始化一个栈,Stack<Integer>stack= newStack<>()3)放入......
  • 《分布式技术原理与算法解析》学习笔记Day07
    分布式锁什么是分布式锁?为了实现分布式互斥,我们需要在某个地方做个标记,这个标记是每个线程都可以看到,当标记不存在时可以设置该标记,当标记被设置后,其他线程只能等待拥有......
  • 关于顺达react主管笔记之学习之创建表单
    顺达主管86378678是当回事的发挥importLogsfrom"./Components/Logs/Logs";importLogsFormfrom"./Components/LogsForm/LogsForm";import'./App.css';constApp=......
  • 算法导论:摊还分析
    基本概念摊还分析也称平摊分析,用于总体考虑分析问题,通过\(n\)次操作来计算平均代价。与平均情况分析的区别:平摊分析不涉及到概率,保证其平摊性能是每个操作在最坏情况下......
  • 一种空间复杂度为$O(\log n)$的线性字符串匹配算法
    记号记\(\empty\)为空字符串序列记\(Q\)为所有字符串序列构成的集合对于\(A\inQ\),记\(|A|\)为其中字符串个数对于\(\begin{cases}1\lel\ler\len\\A=\{a_{1},a_{2......
  • 算法刷题 Day 36 | ● 435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间
    今天的三道题目,都算是重叠区间问题,大家可以好好感受一下。都属于那种看起来好复杂,但一看贪心解法,惊呼:这么巧妙!还是属于那种,做过了也就会了,没做过就很难想出来。不......
  • 关于Java基础-第五天的复习笔记
    1.方法概述1.1方法的概念(理解)方法(method)是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集注意:方法必须先创建才可以使用,该过程成为方法定义......
  • 关于Java基础复习-第二天的总结笔记
    0、类型转换问题类型转换(理解)在Java中,会存在不同类型的数据需要一起参与运算,所以这些数据类型之间是需要相互转换的,分为两种情况:自动类型转换和强制类型转换。自动类型......