1.广度优先搜索BFS
从起点开始一层一层的扩散出去,要实现这个一层一层的扩散就要用到队列的先进先出的思想,所以一般我们都用队列来实现广度优先搜索算法。题目描述:小 A 同学现在被困在了一个迷宫里面,他很想从迷宫中走出来,他可以 向上、向下、向左、向右移动、每移动一格都需要花费 1 秒的时间,不能够走到 边界之外。假设小 A 现在的位置在 S,迷宫的出口在 E,迷宫可能有多个出口。 问小 A 想要走到迷宫出口最少需要花费多少秒?输入样例#:3 3S*#**##*E0 0输出样例#:4
const int N = 105;
char mpt[N][N];
int vis[N][N];
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
struct node{
int x,y;
int step;
};
//广度优先搜索求解
int bfs(int sx,int sy){
memset(vis,0,sizeof(vis));
queue<node> q; //使用数列维护层层发散的优先级
q.push(node{sx,sy,0});
vis[sx][sy] = 1 ;
int ans = -1;
while(!q.empty()){
node now = q.front();
q.pop();
if(mpt[now.x][now.y] == 'E'){
//找到终点
ans = now.step;
break;
}
for(int i=0;i<4;i++){
//上下左右四个方向
int nx = now.x + dir[i][0];
int ny = now.y + dir[i][1];
if((mpt[nx][ny] == '*' or mpt[nx][ny] == 'E')and vis[nx][ny] == 0 ){
q.push(node{nx,ny,now.step+1});
vis[nx][ny] = 1;
}
}
}
return ans;
}
int main()
{
int h,w;
while(scanf("%d%d",&h,&w) != EOF){
if(h ==0 and w ==0) break;
int sx = 0, sy = 0;
memset(mpt,1,sizeof(mpt));
for(int i=1;i<=h;i++){
scanf("%s",mpt[i] + 1);
for(int j = 1;j<=w;j++){
//记录起点坐标
if(mpt[i][j] == 'S') sx = i , sy = j ;
}
}
int ans = bfs(sx,sy);
printf("%d\n",ans);
}
}
递归应用:汉诺塔
题目描述:(n 阶 Hanoi 塔问题)假设有三个分别命名为 A、B、C 的塔座,在塔座 A 上插有 n(n<20)个直径大小各不相同、依小到大编号为 1,2,…,n 的圆盘。现要求将 A 轴上的 n 个圆盘移至塔座 C上并仍按同样顺序叠排,圆盘移动时必须遵循下列规则: 1)每次只能移动一个圆盘; 2)圆盘可以插在 A、B、C 中的任一塔座上; 3)任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。 请通过编程来打印出移动的步骤。输入样例#:520输出样例#:A-->C A-->B C-->B A-->C B-->AB-->C A-->C A-->B C-->B C-->AB-->A C-->B A-->C A-->B C-->BA-->C B-->A B-->C A-->C B-->AC-->B C-->A B-->A B-->C A-->CA-->B C-->B A-->C B-->A B-->CA-->CA-->B A-->C B-->C
int step; //移动步数
void Hano(int n,char a,char b,char c){
if(n==1){
if((step+1)%5==0) cout << a << "-->" << c << endl;
else cout << a << "-->" << c << " ";
step++;
return;
}
Hano(n-1,a,c,b);
Hano( 1 ,a,b,c);
Hano(n-1,b,a,c);
}
int main(){
int n;
while(cin >> n){
if(n == 0) break;
step = 0;
Hano(n,'A','B','C');
cout << endl;
}
}
深度优先搜索 DFS
深度优先搜索的实现形式就是递归,如果把递归的流程画出来可以得到一颗递归树,其实就是一个多叉树。简单来说, BFS 和 DFS 到底有什么区别呢?对于一棵二叉树,BFS 就是二叉树的层次遍历,一层一层的扩展下去。DFS 就是二叉树的中序遍历,一条路走到底,然后回溯走第二条,直到所有路都走完。DFS 一般情况下效率不如 BFS,
题目描述:小 A 同学现在被困在了一个迷宫里面,他很想从迷宫中走出来,他可以 向上、向下、向左、向右移动、每移动一格都需要花费 1 秒的时间,不能够走到 边界之外。假设小 A 现在的位置在 S,迷宫的出口在 E,迷宫可能有多个出口。 问小 A 想要走到迷宫出口最少需要花费多少秒?
输入样例#:3 3S*#**##*E0 0输出样例#:4
用DFS会超时,但写出来供读者与BFS进行比较
using namespace std;
const int N = 105;
char mpt[N][N];
int vis[N][N];
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
int ans;
//深度优先搜索求解
void dfs(int x,int y,int step){
if(step >= ans) return; //当步数超过答案就停止
if(mpt[x][y] == 'E'){
//找到终点
ans = min(ans,step);
return;
}
for(int i=0;i<4;i++){
//上下左右四个方向
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if((mpt[nx][ny] == '*' or mpt[nx][ny] == 'E')and vis[nx][ny] == 0 ){
vis[nx][ny] = 1;
dfs(nx,ny,step+1);
vis[nx][ny] = 0;
}
}
}
int main()
{
int h,w;
while(scanf("%d%d",&h,&w) != EOF){
if(h ==0 and w ==0) break;
int sx = 0, sy = 0;
memset(mpt,0,sizeof(mpt));
memset(vis,0,sizeof(vis));
for(int i=1;i<=h;i++){
scanf("%s",mpt[i] + 1);
for(int j = 1;j<=w;j++){
//记录起点坐标
if(mpt[i][j] == 'S') sx = i , sy = j ;
}
}
ans = 99999999;
dfs(sx,sy,0);
printf("%d\n",ans);
}
}
石油存储:公司在一个时刻调查一个矩形区域,并且创建成一个个的格子用来表示众多正方形块。它然后使用测定设备单个的分析每块区域,决定是否有石油。一块有石油小区域被称为一个 pocket,假设两个 pocket 是相邻的,然后他们就是相同石油块的一部分,石油块可能非常的大并且包涵很多的 pocket。你的任务就是在一个网格中存在多少个石油块。输入首先给出图的大小,然后给出这个图。*代表没有石油,@代表存在石油。输出每种情况下石油块的个数。
输入样例#:5 5****@*@@*@*@**@@@@*@@@**@0 0输出样例#:2其实就是搜索有多少个@块,有 8 个方向,我们直接使用 DFS 搜索即可
const int N = 105;
char mpt[N][N];
int vis[N][N];
int dir[8][2] = {1,0,0,-1,-1,0,0,1,1,1,1,-1,-1,1,-1,-1};
//深度优先搜索求解
int dfs(int x,int y){
vis[x][y] = 1;
for(int i=0;i<8;i++){
//8个方向
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(mpt[nx][ny] == '@' and vis[nx][ny] == 0){
dfs(nx,ny);
}
}
}
int main()
{
int h,w;
while(scanf("%d%d",&h,&w) != EOF){
if(h ==0 and w ==0) break;
int sx = 0, sy = 0;
memset(mpt,0,sizeof(mpt));
memset(vis,0,sizeof(vis));
for(int i=1;i<=h;i++){
scanf("%s",mpt[i] + 1);
}
int ans = 0;
for(int i = 1; i<=h;i++){
for(int j = 1;j <=w;j++){
if(vis[i][j] == 0 and mpt[i][j] =='@'){
ans ++;
dfs(i,j);
}
}
}
printf("%d\n",ans);
}
}