BFS
Basic
主要特点:空间复杂度较高,基于队列
经常用于求最优解的搜索题
经典模型:连通块,最短迷宫路径,曼哈顿距离
Question 01 [ACP2056 山峰与山谷]
主体是广搜模板
难点在于如何判断当前联通块是山峰或山谷
考虑在广搜时进行维护
如果 BFS 检测到的区域不是在当前连通块
就判断其与当前连通块高度的大小关系
进而判断当前连通块是山峰或山谷
注意要先判断大小关系再判断标记数组
(显而易见但一写就 WA )
Code
#include<bits/stdc++.h>
using namespace std;
const int N=1024,dx[10]={0,1,1,1,0,0,-1,-1,-1},dy[10]={0,1,0,-1,1,-1,1,0,-1};
int n,mp[N][N],top,bottom,ff,tt;
bool st[N][N],istop,isbottom;
struct Point{int x,y;}k[N*N];
void bfs(int sx,int sy){
ff=1,tt=0;
k[++tt]={sx,sy};
st[sx][sy]=true;
while(ff<=tt){
int x=k[ff].x,y=k[ff++].y;
for(int i=1;i<=8;i++){
int xx=x+dx[i];
int yy=y+dy[i];
if(xx<1||yy<1||xx>n||yy>n)continue;
if(mp[xx][yy]>mp[x][y]){
istop=0;
continue;
}else if(mp[xx][yy]<mp[x][y]){
isbottom=0;
continue;
}
if(st[xx][yy])continue;
st[xx][yy]=true;
k[++tt]={xx,yy};
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&mp[i][j]);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
if(st[i][j])continue;
istop=1,isbottom=1;
bfs(i,j);
if(istop)++top;
if(isbottom)++bottom;
}
printf("%d %d\n",top,bottom);
return 0;
}
Question 02 [ACP9084 武士风度的牛]
BFS 模板题
重点调一下方向偏差值数组即可
Code
#include<bits/stdc++.h>
using namespace std;
const int N=160,dx[10]={0,2,2,1,1,-1,-1,-2,-2},dy[10]={0,1,-1,2,-2,2,-2,1,-1};
int n,m,ff,tt,fx,fy,sx,sy;
char mp[N][N];
bool st[N][N];
struct Point{int x,y,step;}k[N*N];
int bfs(){
ff=1,tt=0;
k[++tt]={sx,sy,0};
st[sx][sy]=true;
while(ff<=tt){
int x=k[ff].x,y=k[ff].y,step=k[ff++].step+1;
for(int i=1;i<=8;i++){
int xx=x+dx[i],yy=y+dy[i];
if(xx<1||yy<1||xx>n||yy>m)continue;
if(st[xx][yy])continue;
if(mp[xx][yy]=='*')continue;
if(xx==fx&&yy==fy)return step;
st[xx][yy]=true;
k[++tt]={xx,yy,step};
}
}
}
int main(){
scanf("%d%d",&n,&m);
swap(n,m);
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
for(int j=1;j<=m;j++){
if(mp[i][j]=='K')sx=i,sy=j;
if(mp[i][j]=='H')fx=i,fy=j;
}
}
printf("%d",bfs());
return 0;
}
Question [ACP1912 迷宫]
题面就是裸的迷宫板子
思考如何输出路径
考虑记录每一状态前驱的队列下标
递归到达开始状态
在 return 的过程中输出即可
Code
#include<bits/stdc++.h>
using namespace std;
int mp[6][6],dx[6]={0,1,0,-1,0},dy[6]={0,0,1,0,-1},ff,tt;
bool st[6][6];
struct node{int x,y,previd;}k[30];
void print(int id){
if(id==-1)return;
print(k[id].previd);
printf("(%d, %d)\n",k[id].x-1,k[id].y-1);
}
void dfs(int sx,int sy,int fx,int fy){
ff=1,tt=0;
k[++tt]={sx,sy,-1};
st[sx][sy]=true;
while(ff<=tt){
int x=k[ff].x,y=k[ff++].y;
for(int i=1;i<=4;i++){
int xx=x+dx[i],yy=y+dy[i];
if(xx<1||yy<1||xx>5||yy>5)continue;
if(st[xx][yy])continue;
if(mp[xx][yy])continue;
st[xx][yy]=true;
k[++tt]={xx,yy,ff-1};
if(xx==fx&&yy==fy){
print(tt);
return;
}
}
}
}
int main(){
for(int i=1;i<=5;i++)for(int j=1;j<=5;j++)scanf("%d",&mp[i][j]);
dfs(1,1,5,5);
return 0;
}
Question 04 [ACP2520 矩阵距离]
曼哈顿距离模板
将 value 为一的位置入队列
标记 step 即可
ans 数组可与标记数组结合
Code
#include<bits/stdc++.h>
using namespace std;
const int N=1012,dx[6]={0,1,0,0,-1},dy[6]={0,0,1,-1,0};
int n,m,mp[N][N],ff=1,tt=0,st[N][N];
struct Point{int x,y,step;}k[N*N];
int main(){
scanf("%d%d",&n,&m);
char input[N];
for(int i=1;i<=n;i++){
scanf("%s",&input);
for(int j=1;j<=m;j++){
mp[i][j]=input[j-1]-'0';
if(mp[i][j])k[++tt]={i,j,0},st[i][j]=-1;
}
}
while(ff<=tt){
int x=k[ff].x,y=k[ff].y,step=k[ff++].step+1;
for(int i=1;i<=4;i++){
int xx=x+dx[i],yy=y+dy[i];
if(xx<1||yy<1||xx>n||yy>m)continue;
if(st[xx][yy]!=0)continue;
st[xx][yy]=step;
k[++tt]={xx,yy,step};
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)printf("%d ",(st[i][j]==-1)?0:st[i][j]);
puts("");
}
return 0;
}
Question 05[ACP2060 魔板]
本题仍然是明确的 BFS
有明确的转移
难点在于记录状态
本题采用 int 进行存储
写出对应的 A,B,C 函数
Code
#include<bits/stdc++.h>
using namespace std;
const int ten[10]={1,10,100,1000,10000,100000,1000000,10000000};
struct node{int key,step,previd,way;}k[100000];
inline int A(int k){return (k/10000)+(k%10000)*10000;}
inline int B(int k){
int ll=k/10000,rr=k%10000;
ll=(ll%10)*1000+ll/10;
rr=(rr%10)*1000+rr/10;
return ll*10000+rr;
}
inline int C(int k){
int a=k/ten[7]%10;
int b=k/ten[6]%10;
int c=k/ten[5]%10;
int d=k/ten[4]%10;
int e=k/ten[3]%10;
int f=k/ten[2]%10;
int g=k/ten[1]%10;
int h=k/ten[0]%10;
return a*ten[7]+f*ten[6]+b*ten[5]+d*ten[4]+e*ten[3]+g*ten[2]+c*ten[1]+h;
}
map<int,int> st;
char ans[2009];
int cnt=0;
void show(int id){
if(k[id].previd==-1)return;
show(k[id].previd);
ans[++cnt]=(char)k[id].way;
}
void bfs(int sx,int fx){
int ff=1,tt=0;
k[++tt]={sx,0,-1,-1};
st[sx]=114514;
while(ff<=tt){
int key=k[ff].key,previd=ff,step=k[ff++].step+1;
int a=A(key),b=B(key),c=C(key);
if(st[a]!=114514){
st[a]=114514;
k[++tt]={a,step,previd,(int)'A'};
if(a==fx){
printf("%d\n",step);
show(tt);
return;
}
}
if(st[b]!=114514){
st[b]=114514;
k[++tt]={b,step,previd,(int)'B'};
if(b==fx){
printf("%d\n",step);
show(tt);
return;
}
}
if(st[c]!=114514){
st[c]=114514;
k[++tt]={c,step,previd,(int)'C'};
if(c==fx){
printf("%d\n",step);
show(tt);
return;
}
}
}
}
int main(){
st.clear();
int t=0,x,lable[10];
for(int i=1;i<=8;i++)scanf("%d",&lable[i]);
t=lable[1]*ten[7]+lable[2]*ten[6]+lable[3]*ten[5]+lable[4]*ten[4]+lable[8]*ten[3]+lable[7]*ten[2]+lable[6]*ten[1]+lable[5]*ten[0];
if(t==12348765)puts("0"),exit(0);
bfs(12348765,t);
for(int i=1,it=1;i<=cnt;i++,it++){
putchar(ans[i]);
if(it==60)it=0,puts("");
}
return 0;
}
Question 06 [ACP2059 电路维修]
毒瘤题!
本题转移是向四角
重点是电力点其实是在格点上
所以向四周转移是有两种情况
一种是需要拧一下电路
另一种是不需要拧
所以有时可能会导致 step 加一
也有可能不变
所以就不能保证先搜到的一定是答案
本题用到了 Dijstra 思想
用当前最小去松弛其转移点
Code
#include<bits/stdc++.h>
using namespace std;
const int N=507,dx[7]={0,1,1,-1,-1},dy[7]={0,-1,1,-1,1};
char mp[N][N]={};
bool st[N][N];
int n,m;
struct node{
int x,y,step;
};
bool able(int x,int y,int id){
if(id==1)return mp[x+1][y]=='/';
if(id==2)return mp[x+1][y+1]=='\\';
if(id==3)return mp[x][y]=='\\';
if(id==4)return mp[x][y+1]=='/';
puts("Shit!");
return 0;
}
deque<node> q;
int bfs(int sx,int sy){
q.clear();//初始化
st[sx][sy]=true;
q.push_front({sx,sy,0});
while(!q.empty()){
int x=q.front().x,y=q.front().y,step=q.front().step;
q.pop_front();
st[x][y]=true;
if(x==n&&y==m)return step;
for(int i=1;i<=4;i++){
int xx=x+dx[i],yy=y+dy[i];
if(xx<0||yy<0||xx>n||yy>m)continue;
if(st[xx][yy])continue;
if(able(x,y,i))q.push_front({xx,yy,step});
else q.push_back({xx,yy,step+1});
}
}
puts("Fuck!");
return 0;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)for(int j=0;j<=m;j++)st[i][j]=false;
for(int i=1;i<=n;i++)scanf("%s",mp[i]+1);
if((n+m)%2==1)puts("NO SOLUTION");
else if(n+m==0)puts("0");
else printf("%d\n",bfs(0,0));
}
return 0;
}
标签:yy,16,int,tt,st,BFS,2025,xx,10
From: https://www.cnblogs.com/2025ing/p/18675244