深搜和广搜问题
相信这两种搜索大家也经常用,我也是在这根据一个类似迷宫问题来简单描述一下这种思想。
话不多说,直接上题。
题目描述
迷宫是由n行m列的单元格组成(n和m都小于等于50),每个单元格要么是空地,要么是障碍物。你的任务是帮助小哼找到一条从迷宫的起点通往小哈所在位置的最短路径。注意:障碍物是不能走的,用1表示。
输入
第一行输入迷宫的行数为n,列数为m
第2行到第n+1行输入迷宫的状态(0为空地,可以走,1为障碍物,不能走)
最后一行输入起始坐标和终点坐标。
输出
输出最短路径的步数
输入样例
5 4
0 0 1 0
0 0 0 0
0 0 1 0
0 1 0 0
0 0 0 1
1 1 4 3
输出样例
7
这道题大意就是求两点之间最短路径,不外乎就两种思想,要不深搜,要不广搜。那就先深搜试试呗。
#include<iostream>
#include<cstdio>
using namespace std;
int n,m; //迷宫的行数列数
int p,q; //终点坐标
int Min = 99999999; //最小步数
int book[1001][1001]; //记录是否走过
int map[1001][1001]; //记录地图
int next[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
void dfs(int x, int y, int step)
{
if(x < 1 || y < 1 || x > n || y > m)
return;
if(x == p && y == q)
{
if(step < Min)
Min = step;
return ;
}
if(step >= Min)
return;
for(int i = 0; i < 4; i ++)
{
int tx = x + next[i][0];
int ty = y + next[i][1];
//判断下一个点是否已经走过或者为障碍物
if(book[tx][ty] == 0 && map[tx][ty] == 0)
{
book[tx][ty] = 1;
dfs(tx,ty,step + 1);
book[tx][ty] = 0;
}
}
}
int main()
{
int startx,starty;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
scanf("%d",&map[i][j]);
scanf("%d%d",&startx,&starty); //输入起点坐标
scanf("%d%d",&p,&q);
book[startx][starty] = 1;
dfs(startx,starty,0);
cout << Min;
return 0;
}
对于我来说,我是偏向于遇到这种问题直接深搜的。下面是广搜解法。再讲广搜之前我想提下队列的知识。队列是存储数据是先进先出,而广搜的思想也是依赖于队列的,你先把起点放入队列中,然后根据起点所在位置进行下一步扩展,然后把扩展的数据入队列。此时,你得把扩展后的数据继续扩展,直到找到终点为止。
队列代码实现如下:
#include<iostream>
#include<cstdio>
using namespace std;
struct queue{
int data[1001];
int head;
int tail;
};
int main()
{
int n;
cin >> n;
queue q;
q.head = 1;
q.tail = 1;
for(int i = 1; i <= n; i ++)
{
scanf("%d",&q.data[i]);
q.tail ++;
}
while(q.head < q.tail)
{
printf("%d ",q.data[q.head]);
q.head ++;
}
return 0;
}
同样广搜也可解决这题。
代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
int n,m; //迷宫的行数列数
int p,q; //终点坐标
int head,tail; //队列的头和尾
int Min = 99999999; //最小步数
int book[1001][1001]; //记录是否走过
int map[1001][1001]; //记录地图
int next[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
struct queue
{
int x;
int y;
int s; //步数
};
queue qu[10001];//大小看情况而定
void bfs(int x, int y)
{
head = 1,tail = 1;
qu[head].x = x;
qu[head].y = y;
qu[head].s = 0;
tail ++;
int flag = 0;
while(head < tail)
{
for(int k = 0; k < 4; k ++)
{
int tx = qu[head].x + next[k][0];
int ty = qu[head].y + next[k][1];
if(tx < 1 || ty < 1 || tx > n || ty > m)
continue;
if(book[tx][ty] == 0 && map[tx][ty] == 0)
{
book[tx][ty] = 1;
qu[tail].x = tx;
qu[tail].y = ty;
qu[tail].s = qu[head].s + 1;
tail ++;
}
if(tx == p && ty == q)
{
flag = 1;
break;
}
}
if(flag == 1)
break;
head ++; //关键步骤
}
}
int main()
{
int startx,starty;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
scanf("%d",&map[i][j]);
scanf("%d%d",&startx,&starty); //输入起点坐标
scanf("%d%d",&p,&q);
book[startx][starty] = 1;
bfs(startx,starty);
cout << qu[tail - 1].s;
return 0;
}
对于两种解法,我认为唯一的不同点就是深搜的话,如果终点抵达不了的话,就不好判断结束点。而广搜就不一样了,可以在最后判断是否到达了终点。