一.搜索算法
1.定义:搜索算法是利用计算机的高性能来有目的地穷举一个问题的部分或所有的可能情况,从而求出问题的解的一种方法。
2.相比于枚举算法的优点:相比于单纯的枚举算法有了一定的方向性和目标性。算法是在解的空间里,从一个状态转移(按照要求拓展)到其他状态,这样进行下去,将解的空间中的状态遍历,找到答案(目标的状态)。
二.搜索算法的分类
- BFS (广度优先搜索) 利用队列先进先出(FIFO)的性质
- DFS (深度优先搜索) 符合栈的先进后出(FILO)的性质
三.深度优先搜索
I. 对dfs的理解
dfs算法的思想是从一个被选定的点出发一条路走到底,如果得不到目的解,那就返回到上一个节点,然后换一条路继续走到底,直到找到目的解返回或者全部遍历完返回一个事先定好的值。dfs一般借用递归完成整个算法的构造。
II. dfs的实现过程
1 每次取出栈顶元素,对其进行拓展。
2 若栈顶元素无法继续拓展,则将其从栈中弹出。继续1过程。
3 不断重复直到获得目标状态(取得可行解)或栈为空(无解)。
III. 代码实现:
void bfs(){
if(){
return;//首先判断当前位置是否为结果
}
while(){
...//循环每一种方试直到最后的结果
}
return ;
}
四.广度优先搜索
I. 对bfs的理解
bfs算法的思想是从一个被选定的点出发;然后从这个点的所有方向每次只走一步的走到底(即其中一个方向走完一步之后换下一个方向继续走);如果得不到目的解,那就返回事先定好的值,如果找到直接返回目的解。与dfs不同的是,bfs不是运用的递归,而是运用队列实现的。
II. bfs的实现过程
1 每次取出队列首元素(初始状态),进行拓展
2 然后把拓展所得到的可行状态都放到队列里面
3 将初始状态删除
4 一直进行以上三步直到队列为空。
III. 代码实现:
void bfs(){
if:(...){//需要的结果
...
//做出操作
return;//结束
}
...
dfs();
...//具体要怎么搜索
}
五.bfs与dfs的用途与区别
dfs:就是以一种单一方式走到黑,然后通过回溯等得到答案的过程。
bfs:先看有多少种方式可以走,然后先记录每一种方式,再按这种方式一层一层遍历,直到得到最后结果。
二者用途:dfs和bfs大都运用在图的处理上:如迷宫,八皇后 等,在这些类型的题上几乎全需要dfs或bfs来解
区别之处:bfs适合求最短路径,dfs适合求所有答案,
六. DFS和BFS的代码框架(转自https://blog.csdn.net/u011437229/article/details/53188837)
BFS框架
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=100;
bool vst[maxn][maxn]; // 访问标记
int dir[4][2]={0,1,0,-1,1,0,-1,0}; // 方向向量
struct State // BFS 队列中的状态数据结构
{
int x,y; // 坐标位置
int Step_Counter; // 搜索步数统计器
};
State a[maxn];
bool CheckState(State s) // 约束条件检验
{
if(!vst[s.x][s.y] && ...) // 满足条件
return 1;
else // 约束条件冲突
return 0;
}
void bfs(State st)
{
queue <State> q; // BFS 队列
State now,next; // 定义2 个状态,当前和下一个
st.Step_Counter=0; // 计数器清零
q.push(st); // 入队
vst[st.x][st.y]=1; // 访问标记
while(!q.empty())
{
now=q.front(); // 取队首元素进行扩展
if(now==G) // 出现目标态,此时为Step_Counter 的最小值,可以退出即可
{
...... // 做相关处理
return;
}
for(int i=0;i<4;i++)
{
next.x=now.x+dir[i][0]; // 按照规则生成下一个状态
next.y=now.y+dir[i][1];
next.Step_Counter=now.Step_Counter+1; // 计数器加1
if(CheckState(next)) // 如果状态满足约束条件则入队
{
q.push(next);
vst[next.x][next.y]=1; //访问标记
}
}
q.pop(); // 队首元素出队。其实前面取了q.front()就可让队首元素出队了。
}
return;
}
int main()
{
......
return 0;
}
DFS框架
//该DFS 框架以2D 坐标范围为例,来体现DFS 算法的实现思想。
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=100;
bool vst[maxn][maxn]; // 访问标记
int map[maxn][maxn]; // 坐标范围
int dir[4][2]={0,1,0,-1,1,0,-1,0}; // 方向向量,(x,y)周围的四个方向
bool CheckEdge(int x,int y) // 边界条件和约束条件的判断
{
if(!vst[x][y] && ...) // 满足条件
return 1;
else // 与约束条件冲突
return 0;
}
void dfs(int x,int y)
{
vst[x][y]=1; // 标记该节点被访问过
if(map[x][y]==G) // 出现目标态G
{
...... // 做相应处理
return;
}
for(int i=0;i<4;i++)
{
if(CheckEdge(x+dir[i][0],y+dir[i][1])) // 按照规则生成下一个节点
dfs(x+dir[i][0],y+dir[i][1]);
}
return; // 没有下层搜索节点,回溯
}
int main()
{
......
return 0;
}
七.dfs例题:
题意:
两边的人同时开枪,那么我又多少种中弹顺序呢?比如我有100血,而一个人用冲锋枪每发子弹能伤害我30血,另一个人用步枪每发子弹能伤害我45血,那导致我死亡的中弹顺序可能是,30 30 30 45,也可能是 45 45 30,也有可能是45 30 45,等等。当然,血量小于或等于0都算被击倒。
同时要注意,如果两人每次对自己造成的伤害是相同的,但仍被看作不同的死亡顺序,比如玩家有100血量,左右两边的人每次能造成50血量的伤害,那么答案为4,情况分别为:
50 50(左边敌人打中了两枪)。
50 50(右边敌人打中了两枪)
50 50(左边敌人开了第一枪)
50 50(右边敌人开了第一枪)
输入:
本题有多组测试数据。每组占一行,由三个正整数m n hp组成(10=<m<hp<90,10<=n<hp<90)。m代表左边的敌人每次对玩家造成的伤害,n代表右边的敌人每次对玩家造成的伤害,hp代表玩家的血量。
输出:
对于每组输入数据,输出一行,结果为玩家有多少种死亡顺序,即中弹顺序。
思路:
看题意是求出所有方式,所以用dfs,然后,先以第一种方式减血(第一个例子,-45,-45,-45。。。),然后就回溯,继续操作,
#include<iostream>
using namespace std;
int ans=0,l,r,hp;
void dfs(int hp,int l,int r){
if(hp<=0){
ans++;
return;
}
dfs(hp-l,l,r);
dfs(hp-r,l,r);
}
int main(){
while(cin>>l>>r>>hp){
dfs(hp,l,r);
cout<<ans<<endl;
ans=0;
}
}
八. bfs例题
题意:
老王同学深陷一个迷宫,他现在想要逃出去。迷宫 是这样的,在m行n列的矩阵当中,“.”表示可以通过的道路,“#”表示墙,是障碍物所以不能通过。迷宫中S代表起始点,E代表出口。老王每次只向上、向下、向左、向右移动一个单位距离,每次移动一个距离话费的时间是1分钟。请问老王最少花多少时间可以离开迷宫,或者根本就不能离开迷宫?
输入:
本题有多组测试数据,对于每组测试数据:
两个整数mn表示m行n列的迷宫,0<mn<=100
接下来是m行n列的迷宫,其中S表示入口,E表示出口,#表示墙,.表示通路。
输出:
如果老王逃出去话费X分钟,则输出:
Escaped in x minute(s).
如果老王不能逃出去,则输出:
Trapped!
代码:
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
char map[101][101];
int n,m;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
int v[101][101],d[101][101];
queue <char> q;
void bfs(int x,int y){
while(q.size()){
char tq=q.front();
q.pop();
if(tq=='E')
break;
for(int i=0;i<4;i++){
int tx=x+dir[i][0];
int ty=y+dir[i][1];
if(map[tx][ty]=='.'&&v[tx][ty]==0&&tx>=0&&tx<n&&ty>=0&&ty<m){
q.push(map[tx][ty]);
d[tx][ty]=d[x][y]+1;
v[tx][ty]=1;
}
}
}
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
memset(v,0,sizeof(v));
memset(d,0,sizeof(d));
int ex,ey,sx,sy;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
cin>>map[i][j];
if(map[i][j]=='S'){
sx=i;
sy=j;
q.push(map[i][j]);
v[i][j]=1;
}
if(map[i][j]=='E'){
ex=i;
ey=j;
}
}
bfs(sx,sy);
if(d[ex][ey]==0)
cout<<"Trapped!"<<endl;
else
cout<<"Escaped in "<<d[ex][ey]<<" minute(s)."<<endl;
}
}