DFS&&BFS初步
深搜原理
深搜,顾名思义,是深入其中、直取结果的一种搜索方法。
深搜优缺点
- 优点
1、能找出所有解决方案
2、优先搜索一棵子树,然后是另一棵,所以和广搜对比,有着内存需要相对较少的优点
- 缺点
1、要多次遍历,搜索所有可能路径,标识做了之后还要取消。
2、在深度很大的情况下效率不高
-
深搜模板
void DFS() //N代表目前DFS的深度 { if(找到解) //进行相应的操作 { … return; } for(inti=0;i<4;i++) //枚举四个方向 { DFS(N+1); //进入下层递归 } }
迷宫
题目描述
给定一个 N × M N \times M N×M 方格的迷宫,迷宫里有 T T T 处障碍,障碍处不可通过。
在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。
输入格式
第一行为三个正整数 N , M , T N,M,T N,M,T,分别表示迷宫的长宽和障碍总数。
第二行为四个正整数 S X , S Y , F X , F Y SX,SY,FX,FY SX,SY,FX,FY, S X , S Y SX,SY SX,SY 代表起点坐标, F X , F Y FX,FY FX,FY 代表终点坐标。
接下来 T T T 行,每行两个正整数,表示障碍点的坐标。
输出格式
输出从起点坐标到终点坐标的方案总数。
样例 #1
样例输入 #1
2 2 1
1 1 2 2
1 2
样例输出 #1
1
提示
对于 100 % 100\% 100% 的数据, 1 ≤ N , M ≤ 5 1 \le N,M \le 5 1≤N,M≤5, 1 ≤ T ≤ 10 1 \le T \le 10 1≤T≤10, 1 ≤ S X , F X ≤ n 1 \le SX,FX \le n 1≤SX,FX≤n, 1 ≤ S Y , F Y ≤ m 1 \le SY,FY \le m 1≤SY,FY≤m。
#include <bits/stdc++.h>
using namespace std;
int N, M, T;
int ans;
int sx, sy, fx, fy, dx, dy;
int a[11][11], book[11][11];
void dfs(int x, int y)
{
int next[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; //可以直接用二维数组表示路径
int tx, ty, k;
if (x == fx && y == fy) //如果找到了终点,就停止深搜
{
ans++;
return;
}
for (int k = 0; k <= 3; k++)
{
tx = x + next[k][0]; //深搜模板
ty = y + next[k][1];
if (tx < 1 || tx > N || ty < 1 || ty > M) //下一个点是否出界
continue;
if (a[tx][ty] == 0 && book[tx][ty] == 0) //如果该点不是障碍且没有走过
{
book[tx][ty] = 1; //则标记
dfs(tx, ty); //继续深搜
book[tx][ty] = 0; //一路深搜到尽头后返回来取消标记,相当于没走过,然后去搜别的路
}
}
return;
}
int main()
{
cin >> N >> M >> T;
cin >> sx >> sy >> fx >> fy;
book[sx][sy] = 1; //标记起始点为走过
for (int i = 1; i <= T; i++)
{
cin >> dx >> dy;
a[dx][dy] = 1;
}
dfs(sx, sy);
cout << ans;
}
广搜原理
广搜,顾名思义,是多管齐下、广撒网的一种搜索方法
广搜优缺点
- 优点
1、对于解决最短或最少问题特别有效,而且寻找深度小
2、每个结点只访问一遍,结点总是以最短路径被访问,所以第二次路径确定不会比第一次短
- 缺点
1、内存耗费量大(需要开大量的数组单元用来存储状态)
广搜模板
void BFS()
{ … …//初始化起点入队
while(!q.empty()) //判断队是否为空
{ … …//获取队首元素
if(... …){… …}//判断是否是终点
for(int i=0;i<4;i++)//四个方向
{
k.x=p.x+dir[i][0];
k.y=p.y+dir[i][1];
//向各个方向走一步
if(judge())//判断能不能走
{
… …//各种处理
vis[k.x][k.y]=1; //标记
q.push(k); //入队
}
}
}
}
马的遍历
题目描述
有一个 n × m n \times m n×m 的棋盘,在某个点 ( x , y ) (x, y) (x,y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。
输入格式
输入只有一行四个整数,分别为 n , m , x , y n, m, x, y n,m,x,y。
输出格式
一个 n × m n \times m n×m 的矩阵,代表马到达某个点最少要走几步(不能到达则输出 − 1 -1 −1)。
样例 #1
样例输入 #1
3 3 1 1
样例输出 #1
0 3 2
3 -1 1
2 1 4
提示
数据规模与约定
对于全部的测试点,保证 1 ≤ x ≤ n ≤ 400 1 \leq x \leq n \leq 400 1≤x≤n≤400, 1 ≤ y ≤ m ≤ 400 1 \leq y \leq m \leq 400 1≤y≤m≤400。
#include <bits/stdc++.h>
using namespace std;
bool book[401][401]; //标记是否走过
int n, m;
int ans[401][401]; //用来储存答案
int x_next[8] = {2, 1, 1, 2, -1, -2, -2, -1};
int y_next[8] = {1, 2, -2, -1, 2, 1, -1, -2};
struct queue
{
int x, y;
} que[40001]; //构建bfs的队列
int check(int x, int y)
{
if (x < 1 || x > n || y < 1 || y > m)
return 0;
return 1;
} //判断是否越界
void bfs(int x, int y)
{
int head = 0, tail = 1; //队列指针一头一尾
int sum = 0; //步数清零
que[1].x = x;
que[1].y = y;
//初始点入队
book[x][y] = 1;
//标记初始点
ans[x][y] = 0;
while (head < tail) //搜完了就退出
{
head++; //首项出队
sum = ans[que[head].x][que[head].y] + 1;
//标记步数
for (int i = 0; i < 8; i++)
{
int tx = que[head].x + x_next[i];
int ty = que[head].y + y_next[i];
if (check(tx, ty) && !book[tx][ty]) //如果该点不在界外,而且未走过
{
tail++;
que[tail].x = tx; //将该点加入队列尾部
que[tail].y = ty;
book[tx][ty] = 1;
ans[que[tail].x][que[tail].y] = sum; //存储答案
}
}
}
}
int main()
{
int x, y;
cin >> n >> m >> x >> y;
memset(ans, -1, sizeof(ans));
bfs(x, y);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cout << ans[i][j] << " ";
}
cout << endl;
}
}