作为一个算法初学者,简单写一下对搜索的感受和经验。
搜索分为深搜和广搜两种,下面会分别介绍一下。
深搜(DFS)
从一个顶点(A)开始,标记A已经遍历,寻找临近A且没有遍历过的点(B),如果找到则继续寻找(即将B代入A),如果找不到则结束本次搜索
小小的一个提醒(提醒虽小,看懂的都是人才)
我设置了四个数组,分别解释一哈。(好好想想为什么要设置四个呢?)
brr[][]单纯的存一下地图(所以地图不能改)
flag[][]标记坐标是否可以走(所以flag会经常变。渣数组,经常变)
minn[][]存当前路径
ans[][]存答案路径
贴一段算法模板
// DFS模板
int a,b,s=0,mink=100;
int brr[10][10];
int flag[10][10],ans[100],minn[100];
int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}};///可以走的几个方向
void DFS(int x,int y,int k)
{
if(x==4&&y==4){///到达目的地
if(k<mink){///判断是不是最短的
mink=k;
for(int i=0;i<=k;i++)
ans[i]=minn[i];
}
return;
}
for(int i=0;i<4;i++){///遍历所以方向
int ix=x+dis[i][0];
int iy=y+dis[i][1];
if(ix>=0&&ix<=4&&iy>=0&&iy<=4&&flag[ix][iy]==0&&brr[ix][iy]==0){///判断条件
flag[ix][iy]=1;///下一步标记走过
minn[k]=ix*10+iy;///存当前的坐标
DFS(ix,iy,k+1);///判断下一步
flag[ix][iy]=0;///解放坐标,方便下一种的可能
}
}
}
搞一个完整的模板(神特么有用)
///介绍一下问题,一个5*5的图,从(0,0)到(4,4)的最短路,并打印
#include<iostream>
#include<cstdlib>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<stack>
#include<queue>
#include<iomanip>
#include<map>
#include<set>
#include<functional>
using namespace std;
int a,b,s=0,mink=100;
int brr[10][10];
int flag[10][10],ans[100],minn[100];
int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}};///可以走的几个方向
void DFS(int x,int y,int k)
{
if(x==4&&y==4){///到达目的地
if(k<mink){///判断是不是最短的
mink=k;
for(int i=0;i<=k;i++)
ans[i]=minn[i];
}
return;
}
for(int i=0;i<4;i++){///遍历所以方向
int ix=x+dis[i][0];
int iy=y+dis[i][1];
if(ix>=0&&ix<=4&&iy>=0&&iy<=4&&flag[ix][iy]==0&&brr[ix][iy]==0){///判断条件
flag[ix][iy]=1;///下一步标记走过
minn[k]=ix*10+iy;///存当前的坐标
DFS(ix,iy,k+1);///判断下一步
flag[ix][iy]=0;///解放坐标,方便下一种的可能
}
}
}
int main()
{
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
cin >> brr[i][j];
memset(flag,0,sizeof(flag));
DFS(0,0,0);
printf("(%d, %d)\n",0,0);
for(int i=0;i<mink;i++)
printf("(%d, %d)\n",ans[i]/10,ans[i]%10);
return 0;
}
广搜(BFS)
从第一个点开始进行判断,符合条件就压进队列,直到队列为空或目的达成
贴一段模板
//BFS模板
struct data{
int x,y,k;
}now,well;
int a,b,s=0,mink=100;
int flag[10][10],brr[10][10],ans[100],minn[100];
int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}};///可以走的几个方向
int BFS(data A)
{
memset(flag,0,sizeof(flag));///标记点是否走过的地图
A.k=0;///初始化
queue<data> Q;
Q.push(A);///恶梦的开始
flag[A.x][A.y]=1;///标记初始点已经走过了
while(!Q.empty()){
now=Q.front();///处理第一个数据
Q.pop();///抛弃第一个数据
if(now.x==4&&now.y==4)///判断是否到达目的地
return now.k;
for(int i=0;i<4;i++){
well.x=now.x+dis[i][0];
well.y=now.y+dis[i][1];
if(well.x>=0&&well.x<=4&&well.y>=0&&well.y<=4&&brr[well.x][well.y]==0&&flag[well.x][well.y]==0){
flag[well.x][well.y]=now.k;///标记初始点已经走过了,顺便标记这个点是第几步走的
well.k=now.k+1;///总步数加1
Q.push(well);///压进队列
}
}
}
}
搞一个完整的模板(神特么有用)
//介绍一下问题,一个5*5的图,从(0,0)到(4,4)的最短路
#include<iostream>
#include<cstdlib>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<stack>
#include<queue>
#include<iomanip>
#include<map>
#include<set>
#include<functional>
using namespace std;
struct data{
int x,y,k;
}now,well;
int a,b,s=0,mink=100;
int flag[10][10],brr[10][10],ans[100],minn[100];
int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}};///可以走的几个方向
int BFS(data A)
{
memset(flag,0,sizeof(flag));///标记点是否走过的地图
A.k=0;///初始化
queue<data> Q;
Q.push(A);///恶梦的开始
flag[A.x][A.y]=1;///标记初始点已经走过了
while(!Q.empty()){
now=Q.front();///处理第一个数据
Q.pop();///抛弃第一个数据
if(now.x==4&&now.y==4)///判断是否到达目的地
return now.k;
for(int i=0;i<4;i++){
well.x=now.x+dis[i][0];
well.y=now.y+dis[i][1];
if(well.x>=0&&well.x<=4&&well.y>=0&&well.y<=4&&brr[well.x][well.y]==0&&flag[well.x][well.y]==0){
flag[well.x][well.y]=now.k;///标记初始点已经走过了,顺便标记这个点是第几步走的
well.k=now.k+1;///总步数加1
Q.push(well);///压进队列
}
}
}
}
int main()
{
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
cin >> brr[i][j];
data data;
data.x=0;
data.y=0;
int s=BFS(data);
cout << s << endl;
return 0;
}
广搜的特点在于处理方式,并不是同时处理一层数据(只有人脑才能并线处理这么多数据),而是把一个个数据全都存起来(压入队列),一个个处理。想象一下,一个管子,前半部分是“旧数据”,后半部分压入“新数据”。
总结
搜索本身不是问题,难点在于对题目的理解和判断条件的运用,慢慢练,会好的。
第二次总结
搜索是个好东西,只是看似简单而已,这是第二次整理留下了的,我觉得可能还会有下一次。
第三次总结
刷了好多题,觉得搜索越来越不想搜索了,心态炸了!