搜索与回溯
来源:互联网 发布:java编写一个小程序 编辑:程序博客网 时间:2024/05/21 03:25
概论
搜索与回溯算法,就像是在迷宫里不断寻找正确前进路径的方式。
搜索与回溯也是信息学竞赛中常会有的算法(algorithm)。于是,诸位作为新生代的大佬,哪里能不好好学习一下搜索回溯算法呐?!!!
这里讲的是深度搜索策略(dfs);
dfs就是一条路走到黑,不撞南墙不回头!!!
就类似迷宫问题: 进入迷宫后,先随意选择一个前进方向,一步步向前试探前进,如果碰到死胡同,说明前进方向已无路可走,这时,首先看其它方向是否还有路可走,如果有路可走,则沿该方向再向前试探;如果已无路可走,则返回一步,再看其它方向是否还有路可走;如果有路可走,则沿该方向再向前试探。按此原则不断搜索回溯再搜索,直到找到新的出路或从原路返回入口处无解为止。
递归回溯法算法框架[一]
int Search(int k){ for (i=1;i<=算符种数;i++) if (满足条件) { 保存结果 if (到目的地) 输出解; else Search(k+1); 恢复:保存结果之前的状态{回溯一步} }}
递归回溯法算法框架[二]
int Search(int k){ if (到目的地) 输出解; else for (i=1;i<=算符种数;i++) if (满足条件) { 保存结果; Search(k+1); 恢复:保存结果之前的状态{回溯一步} }}
以上是两个框架,就是搜索回溯算法的框架,看不懂吗?没关系,结合着它一起看看题目和代码。
例题:
例题一
设有n个整数的集合{1,2,…,n},从中取出任意r个数进行排列(r<=n),试列出所有的排列。
输入:一行,n和r。
输出:所有的排列,每种占一行。
输入样例:
3 3
输出样例:
1 2 31 3 22 1 32 3 13 1 23 2 16
我们分析一下这个题哈:首先,你要从1开始搜,搜啊搜,搜啊搜,当1的情况全部搜完事时,再从2开始搜········
以下是参考程序:
#include<iostream>#include<cstdio>#include<iomanip>//库文件名 using namespace std;int num=0,a[10001]={0},n,r;//先定义一下全局变量 ,b数组是bool类型、用于判断,以防止搜重 bool b[100001]={0};int search(int);int print();//以上是函数声明 int main(){ cin>>n>>r; //取到n,r得值 search(1); //开始搜索,从"1"开始 cout<<num<<endl;}int search(int k){ int i; for(i=1;i<=n;i++)//n个数,从一到n都搜索一遍,for循环内的是搜索以ni为开头的数 (定义ni是第i个数) 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 i=1;i<=r;i++) cout<<setw(3)<<a[i]; //setw(3)是以空三个格形式输出 cout<<endl;}
这里是这个程序运行情况
注意:搜索与回溯这一方面的算法,是需要大量的模拟 的;
模拟模拟模拟,特别重要哦!!!!!
例题二:
任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。
输入:n
输出:n这个数的拆分方式,并输出总共有多少种拆分方式。
输入样例:
7
输出样例:
7=1+1+1+1+1+1+17=1+1+1+1+1+27=1+1+1+1+37=1+1+1+2+27=1+1+1+47=1+1+2+37=1+1+57=1+2+2+27=1+2+47=1+3+37=1+67=2+2+37=2+57=3+4total=14
以下为参考程序;
#include<iostream>#include<fstream>int a[10001]={1},n,total;using namespace std;ifstream fin ("in.in");ofstream fout ("out.out");int print(int t){ //这是一个输出函数 fout<<n<<"="; for(int i=1;i<=t-1;i++) fout<<a[i]<<"+"; fout<<a[t]<<endl; total++; }int search(int s,int t){ int i; for(i=a[t-1];i<=s;i++){ if(i<n){ a[t]=i; s-=i; if(s==0) print(t); //如果到达目的地的话,就输出 else search(s,t+1); //如果没到目的地的话,就在搜索下一条路。 s+=i; //回溯阶段,很重要很重要很重要 } }}int main(){ fin>>n; search(n,1); //搜索 fout<<total;}
这里是程序运行结果,用文件流方式写的
这两个的例题是很经典的,一定要自已模拟一下,手动模拟!!!!
八皇后问题:
要在国际象棋棋盘中放八个皇后,使任意两个皇后都不能互相吃。(提示:皇后能吃同一行、同一列、同一对角线的任意棋子。)
放置第i个(行)皇后的算法为:int search(i); { int j; for (第i个皇后的位置j=1;j<=8;j++ ) //在本行的8列中去试 if (本行本列允许放置皇后) { 放置第i个皇后; 对放置皇后的位置进行标记; if (i==8) 输出 //已经放完个皇后 else search(i+1); //放置第i+1个皇后 对放置皇后的位置释放标记,尝试下一个位置是否可行; } }
显然问题的关键在于如何判定某个皇后所在的行、列、斜线上是否有别的皇后;可以从矩阵的特点上找到规律,如果在同一行,则行号相同;如果在同一列上,则列号相同;如果同在/ 斜线上的行列值之和相同;如果同在\ 斜线上的行列值之差相同;从下图可验证:
考虑每行有且仅有一个皇后,设一维数组A[1..8]表示皇后的放置:第i行皇后放在第j列,用A[i]=j来表示,即下标是行数,内容是列数。例如:A[3]=5就表示第3个皇后在第3行第5列上。判断皇后是否安全,即检查同一列、同一对角线是否已有皇后,建立标志数组b[1..8]控制同一列只能有一个皇后,若两皇后在同一对角线上,则其行列坐标之和或行列坐标之差相等,故亦可建立标志数组c[1..16]、d[-7..7]控制同一对角线上只能有一个皇后。
如果斜线不分方向,则同一斜线上两皇后的行号之差的绝对值与列号之差的绝对值相同。在这种方式下,要表示两个皇后I和J不在同一列或斜线上的条件可以描述为:A[I]<>A[J] AND ABS(I-J)<>ABS(A[I]-A[J]){I和J分别表示两个皇后的行号}
下面放代码:
#include<cstdio>#include<iostream>#include<cstdlib>#include<iomanip>using namespace std;bool d[100]={0},b[100]={0},c[100]={0};int sum=0,a[100];int search(int);int print();int main(){ search(1); //从第1个皇后开始放置}int search(int i){ int j; for (j=1;j<=8;j++) //每个皇后都有8位置(列)可以试放 if ((!b[j])&&(!c[i+j])&&(!d[i-j+7])) //寻找放置皇后的位置 //由于C++不能操作负数组,因此考虑加7 { //放置皇后,建立相应标志值 a[i]=j; //摆放皇后 b[j]=1; //宣布占领第j列 c[i+j]=1; //占领两个对角线 d[i-j+7]=1; if (i==8) print(); //8个皇后都放置好,输出 else search(i+1); //继续递归放置下一个皇后 b[j]=0; //递归返回即为回溯一步,当前皇后退出 c[i+j]=0; d[i-j+7]=0; }}int print(){ int i; sum++; //方案数累加1 cout<<"sum="<<sum<<endl; for (i=1;i<=8;i++) //输出一种方案 cout<<setw(4)<<a[i]; cout<<endl; }
- 搜索与回溯 5.6
- 搜索与回溯 心得
- 搜索与回溯
- 搜索与回溯 字符序列
- 回溯法搜索总结与常见问题
- 穷举搜索:回溯与深搜
- 搜索与回溯5.2——排列
- 搜索与回溯 上机训练 4
- 搜索与回溯 6.装载问题
- 搜索与回溯 最佳调度问题
- 浅谈回溯与深度优先搜索
- 搜索-回溯
- C++搜索与回溯算法之红与黑
- 栈:深度优先搜索与回溯算法求解迷宫
- 1006.Team Rankings 栈与回溯 简单 5!搜索
- 五星填数与深度优先搜索回溯思想
- 搜索与回溯5.3——自然数拆分
- 搜索与回溯5.6——工作效益
- Hive学习之HiveServer2服务端配置与启动,允许远程连接
- 20171030
- jvm内存溢出和参数设置
- mysql软件在Linux下的安装
- 每日一练 20171103
- 搜索与回溯
- Linux中的ftp服务
- python基础------正则表达式
- react的脚手架工具
- 20171031
- 中国 2017 Google 开发者大会来了!
- Word打印的三个技巧 打印指定页 缩进文档 打印当前页示例介绍
- CSS中可以和不可以继承的属性
- 前端老司机与算法的四个故事