bfs
参加过一些ac的竞赛了,一直搞不清楚bfs,数据结构方面对队列的知识也大多了解,但是一直对bfs不怎么感冒,这两天看了很多文章终于有点懂了- -
大致模板
1.定义地图数组mp[]以及其对应的visit数组vis[]
2.定义结构体 存放坐标以及步数信息
3.定义移动数组
5.bfs(起点、终点)
{
queue<**> q; 创建队列
起点进队列 q.push(起点)
更新vis数组
定义结构体对象t,承载队头
队头出队
while(!empty())
{
①if(到达终点?) return t.步数; 在这不用+1
for(i=0;i<4;i++){
②if(到达终点?) return t.步数+1;此步骤与①处等效
if(判断位置合法?) continue;
结构体对象t1承载新坐标属性(xy step要+1 )
t1入队
}
}
return -1;遍历完后依然没到终点
}
题目1
这是一个关于二维迷宫的题目。我们要从迷宫的起点 ‘S’ 走到终点 ‘E’,每一步我们只能选择上下左右四个方向中的一个前进一格。 ‘W’ 代表墙壁,是不能进入的位置,除了墙壁以外的地方都可以走。迷宫内的 ‘D’ 代表一道上锁的门,只有在持有钥匙的时候才能进入。而 ‘K’ 则代表了钥匙,只要进入这一格,就会自动地拿到钥匙。最后 ‘.’ 则是代表空无一物的地方,欢迎自在的游荡。
本题的迷宫中,起点、终点、门跟钥匙这四个特殊物件,每一个恰好会出现一次。而且,此迷宫的四周 (最上面的一行、最下面的一行、最左边的一列以及最右边的一列) 都会是墙壁。
请问,从起点到终点,最少要走几步呢?
输入描述
输入的第一行有两个正整数H, W,分别代表迷宫的长跟宽。
接下来的H行代表迷宫,每行有一个长度恰为W的字串,此字串只包含'S'
,'E'
,'W'
,'D '
,'K'
,'.'
这几种字元。
输出描述
请在一行中输出一个整数代表答案,如果无法从起点走到终点,请输出-1。
示例
输入
4 12
WWWWWWWWWWWW
WE.W.S..W.KW
W..D..W....W
WWWWWWWWWWWW
输出
20
输入
6 6
WWWWWW
WEWS.W
W.WK.W
W.WD.W
W.W..W
WWWWWW
输出
-1
题目1代码
#include<bits/stdc++.h>
using namespace std;
char mp[500][500]; //注意地图数组不能叫map map是关键字c++会报错
int vis[500][500];
int h, w; //长和宽 其实对应着行列
int dx[] = { 1,-1,0,0 }; //右左下上
int dy[] = { 0,0,1,-1 };
struct ren
{
int x;
int y;
int step = 0;
}st,ed,key,door; //start end key钥匙 door 门
int bfs(ren beg, ren end)
{
queue<ren> q;
q.push(beg);
vis[beg.x][beg.y] = 1;
while (!q.empty())
{
ren temp, t;
temp = q.front();
q.pop();
//if (temp.x == end.x && temp.y == end.y) return temp.step;
for (int i = 0; i < 4; i++)
{
int xx = temp.x + dx[i];
int yy = temp.y + dy[i];
t = temp;
if (xx == end.x && yy == end.y) return temp.step+1;
if (xx < 0 || yy < 0 || xx >= h || yy >= w)//越界
continue;
if (vis[xx][yy] || mp[xx][yy] == 'D' || mp[xx][yy] == 'W') //走过或者是这个位置是门或者墙
continue;
t.x = xx;
t.y = yy;
t.step++; //更新新的节点
q.push(t); //入队
vis[xx][yy] = 1;
}
}
return -1;
}
int main()
{
cin >> h >> w;
for (int i = 0; i < h; i++) //录入地图
{
for (int j = 0; j < w; j++)
{
cin >> mp[i][j];
if (mp[i][j] == 'S') st.x = i, st.y = j;
if (mp[i][j] == 'E') ed.x = i, ed.y = j;
if (mp[i][j] == 'K') key.x = i, key.y = j;
if (mp[i][j] == 'D') door.x = i, door.y = j;
}
}
//不走钥匙
memset(vis, 0, sizeof(vis));
int ans1 = bfs(st, ed);
//找钥匙
memset(vis, 0, sizeof(vis));
int ans2 = bfs(st, key);
mp[door.x][door.y] = '.';
//钥匙找门
memset(vis, 0, sizeof(vis));
int ans3 = bfs(key, door);
//men找出口
memset(vis, 0, sizeof(vis));
int ans4 = bfs(door, ed);
if (ans1 == -1) //直接走不成功
{
if (ans2 == -1 || ans3 == -1 || ans4 == -1) //迂回路线也不成功
{
cout << "-1" << endl;
}
else
{
cout << ans2 + ans3 + ans4<<endl;
}
}
else {//都可以走出来,就看哪个步数更少
cout << min(ans1, ans2 + ans3 + ans4)<<endl;
}
return 0;
}
题目二
有一个n ×m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步
输入要求
一行四个数据,棋盘的大小和马的坐标
输出要求
一个n×m的矩阵,代表马到达某个点最少要走几步(左对齐,宽5格,不能到达则输出-1)
示例
输入
3 3 1 1
输出
0 3 2
3 -1 1
2 1 4
老规矩,搞各种数组,搞队列,然后开始排列
#include<bits/stdc++.h>
using namespace std;
const int maxn = 500;
int m, n,sx,sy;//地图
//直往下和往右走
int stp[maxn][maxn];
int dir[8][2] = { {1,2},{-1,2},{2,1},{-2,1},{2,-1},{-2,-1},{1,-2},{-1,-2}};//马可以走的八个方向
struct pos { //坐标
int x;
int y;
int step;
};
bool judge(int p, int q)
{
if (p<1 || q<1 || p>m || q>n)
{
return false;
}
else if (stp[p][q] != -1)
{
return false;
}
else
return true;
}
void bfs()
{
queue<pos> que;
pos temp1 = { sx,sy,0 };
que.push(temp1);//jin dui
stp[sx][sy] = 0;
while (!que.empty()) { //队内元素为空
pos f = que.front();
que.pop();
for (int i = 0; i < 8; i++)
{
int dx = f.x + dir[i][0];
int dy = f.y + dir[i][1];
if (dx<1 || dy<1 || dx>m || dy>n) continue;
if (stp[dx][dy] != -1)continue;
pos temp = { dx,dy,f.step + 1 };
//进队
que.push(temp);
//改进步数
stp[temp.x][temp.y] = temp.step;
/* 下面注释的这些也可以 替换42-52行即可
//走一步
if (judge(f.x+dir[i][0], f.y + dir[i][1]))
{ //建立新节点存储相关信息
pos temp = { f.x + dir[i][0],f.y + dir[i][1],f.step + 1 };
//进队
que.push(temp);
//改进步数
stp[temp.x][temp.y] = temp.step;
}
*/
}
}
}
int main()
{
cin >> m >> n>>sx>>sy;
memset(stp, -1, sizeof(stp));
//vis[sx][sy] = 1;
bfs();
//输出
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
cout << stp[i][j];
if (j != n) cout << " ";
}
cout << endl;
}
}
题目三
二维矩阵,问从1,1位置到m,n位置有几条线路
ps:矩阵下标为双偶数的禁止路过,比如(2,2)、(4,4)等点
只能向右或者向下路行 .
输入要求
两个整数表示矩阵大小
输出要求
一个证书表示路线数量
示例
输入
3 4
输出
2
* | |||
---|---|---|---|
* |
#include<bits/stdc++.h>
using namespace std;
int m, n;//地图
//直往下和往右走
int dir[2][2] = { {0,1},{1,0} };
int ans = 0;
struct pos { //坐标
int x;
int y;
};
void bfs()
{
queue<pos> que;
que.push({ 1, 1 });//jin dui
while (!que.empty()) { //队内元素为空
pos f = que.front();
que.pop();
for (int i = 0; i < 2; i++)
{ //走一步
int dx = f.x + dir[i][0];
int dy = f.y + dir[i][1];
//越界
if (dx > m || dy > n) continue;
//坐标规范
if (dx % 2 == 0 && dy % 2 == 0) continue;
//到达终点
if (dx == m && dy == n) ans++;
//入队
que.push({ dx,dy });
}
}
}
int main()
{
cin >> m >> n;
bfs();
cout << ans;
}