01 BFS 笔记

发现这个东西在特定情况下是非常有用的,所以记录一下子。

只讨论最短路时的应用,但是这个东西明显不局限于最短路,可以抽象的模型都是可以的。

定义

这个东西同样叫作双端队列 bfs,顾名思义,这种 bfs 里边使用的是一个双端队列。

在一张边权都是 1 的图上搞最短路,如果我们使用双端队列 bfs 的话,很明显我的每个状态在第一次被访问并且入队的时候就是它的最短路了,这个东西我们很容易做到 \(O(n)\) 级别,然而如果边权是 \(0/1\) 呢?

我们把边权为 0 扩展到的点放到前边, 边权为 1 扩展到的点放到后边,这个样子前边的一定就是答案,避免的重复访问,这个东西的复杂度就非常优秀。

例题

对于一艘在一片巨大的水域上的船来说,水流可能非常危险,但如果仔细规划路线,它们也可以成为船只前往终点的动力。你的任务就是帮助规划路线。

在湖面上每个点都有一个水流方向,你可以选择向水流方向移动一个单位,不用花费能量,或是向其他方向移动一个单位,花费 \(1\) 单位的能量。船只能向以下八个方向移动:东、南、西、北、东南、东北、西南、西北。船只不可以离开海面的边界。

你需要制定一个策略,以最少的能量消耗到达目的地。

给定两个整数 \(n,m\) 和一个 \(n\times m\) 的矩阵表示湖面。

\(q\) 次询问,每次询问给出四个数 \(r_s,c_s,r_d,c_d\),求从 \((r_s,c_s)\) 移动到 \((r_d,c_d)\) 至少需要多少点能量。

\(1\le n,m\le 10^3,1\le q\le 50\)

湖面用一个矩形网格来表示,第一行包含两个整数 \(r,c\),表示该网格的行数和列数,\(r,c\le 1000\)

\(2\) 到 第 \(r+1\) 行,每行包含 \(c\) 个在 \([0,7]\) 之间的整数字符,表示湖面。字符 \(\texttt{0}\) 表示水流向北,字符 \(\texttt{1}\) 表示向东北,\(\texttt{2}\) 表示向东,依此类推,按顺时针方向排列。

具体方向如下所示(* 表示当前所在的位置):

7 0 1
 \|/
6-*-2
 /|\
5 4 3

\(r+2\) 行包含一个整数 \(n\),表示将要航行的次数,\(n\le 50\)

接下来 \(n\) 行,每行包含四个整数 \(r_s,c_s,r_d,c_d\),表示一次从 \((r_s,c_s)\)\((r_d,c_d)\) 的航行。湖面下标从 \(1\) 开始。

对于每个询问,输出一行一个整数,表示至少需要的能量消耗。

这个东西没啥说的,就直接打板子就行了。

代码↓

#include <bits/stdc++.h>
using namespace std;
const int MN=1145;
int a[MN][MN], n, m;
int vis[MN][MN], dis[MN][MN];
int sx, sy, ex, ey, Q;
int dx[8]={-1,-1,0,1,1,1,0,-1};
int dy[8]={0,1,1,1,0,-1,-1,-1};
void bfs(){
	memset(vis,false,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
	deque <pair<int,int>> q;
	while(!q.empty()) q.pop_front();
	dis[sx][sy]=0; q.push_front({sx,sy});
	while(!q.empty()){
		int x=q.front().first, y=q.front().second; q.pop_front();
		if(vis[x][y]) continue; vis[x][y]=true;
		for(int k=0; k<8; ++k){
			int nx=x+dx[k], ny=y+dy[k];
			if(nx<1||ny<1||nx>n||ny>m) continue;
			int flag=false;
			if(a[x][y]!=k) flag=true;
			if(dis[nx][ny]>dis[x][y]+flag){
				dis[nx][ny]=dis[x][y]+flag;
				if(flag==0) q.push_front({nx,ny});
				else q.push_back({nx,ny});
			}
		}
	}
}
int main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n>>m;
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=m; ++j){
			char c; cin>>c;
			a[i][j]=c-'0';
		}
	}
	cin>>Q; while(Q--){
		cin>>sx>>sy>>ex>>ey;
		bfs(); cout<<dis[ex][ey]<<'\n';
	}
	return 0;
}
posted @ 2025-09-26 10:45  BaiBaiShaFeng  阅读(8)  评论(0)    收藏  举报
Sakana Widget右下角定位