一.什么是搜索与回溯算法
搜索与回溯是计算机解题中常用的算法,很多问题无法根据某种确定的计算法则来求解,可以利用搜索与回溯的技术求解。回溯是搜索算法中的一种控制策略。它的基本思想是:为了求得问题的解,先选择某一种可能情况向前探索,在探索过程中,一旦发现原来的选择是错误的,就退回一步重新选择,继续向前探索,如此反复进行,直至得到解或证明无解。
二.搜索回溯法算法框架
1.
int search(int k){
for(int i=1;i<=算符种数;i++){
if(满足条件){
保存结果
if(到目的地){
输出解
}else{
search(k+1);
恢复:保存结果之前的状态(回溯一步)
}
}
}
}
2.
int search(int k){
if(到目的地){
输出解
}else{
for(int i=1;i<=算符种数;i++){
if(满足条件){
保存结果
search(k+1);
恢复:保存结果之前的状态(回溯一步)
}
}
}
}
三.例题
题目一
素数环:将1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数。
算法分析
非常明显,这是一道回溯的题目。从1开始,每个空位有20种可能,只要填进去的数合法:与前面的数不相同;与左边相邻的数的和是一个素数。第20个数还要判断和第1个数的和是否素数。
算法流程
(1)数据初始化;(2)递归填数:判断第i个数填入是否合法
①如果合法:填数;判断是否到达目标(20个已填完):是打印结果;不是:递归填下一个
②如果不合法:选择下一种可能
代码
#include<bits/stdc++.h>
using namespace std;
bool b[21];
int total=0,a[21];
bool zhi(int n,int m){
int ji=n+m;
if(ji==0||ji==1){
return false;
}
for(long long i=2;i*i<=ji;i++){
if(ji%i==0){
return false;
}
}
return true;
}
int print(){
total++;
cout << "<" << total << ">";
for(int i=1;i<=20;i++){
cout << a[i] << " ";
}
cout << endl;
}
int search(int t){
for(int i=1;i<=20;i++){
if(zhi(a[t-1],i)&&(!b[i])){
a[t]=i;
b[i]=1;
if(t==20){
if(zhi(a[20],a[1])){
print();
}else{
search(t+1);
}
b[i]=0;
}
}
}
}
int main(){
search(1);
cout << total << endl;
return 0;
}
题目二
在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方。
无输入
按给定顺序和格式输出所有八皇后问题的解(见样例)。
输出样例
No. 1
1 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
No. 2
1 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 1 0 0 0 0 0
算法分析
放置第i个(行)皇后的算法为:
int search(int i){
for(第i个皇后的位置j=1;j<=8;j++){//在本行的8列中去试
if(本行本列允许放置皇后){
放置第i个皇后;
对放置皇后的位置进行标记;
if(i==8){//已经放完皇后
输出
}else{
search(i+1);//放置第i+1个皇后
对放置皇后的位置释放标记,尝试下一个位置是否可行;
}
}
}
}
代码
#include<bits/stdc++.h>
using namespace std;
bool d[17],b[9],c[17];
int sum=0,a[9];
int print(){
sum++;
cout << "sum=" << sum << endl;
for(int k=1;k<=8;k++){
cout << a[k] << " ";
}
cout << endl;
}
int search(int i){
for(int j=1;j<=8;j++){
if((!b[j])&&(!c[i+j])&&(!d[i-j+7])){
a[i]=j;
b[j]=1;
c[i+j]=1;
d[i-j+7];//防止数组下标是负数
if(i==8){
print();
}else{
search(i+1);
b[j]=0;
c[i+j]=0;
d[i-j+7]=0;
}
}
}
}
int main(){
search(1);
return 0;
}