BFS 2025/1/16
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 思想
用当前最小去松弛其转移点
正常 Dijstra 是需要用 priority_queue 的
但在此题中会 TLE
我们要保证队列首位是最小的
而根据题意整个队列中最大和最小的元素最多差一
因此我们可以把扩展出来而没有增加 step 的元素直接放在队首
(因为原来队首的 step 就是最小的,而如果不加一 step 就不会变,仍然是最小的)
反之若增加了 step 就放在队尾
所以我们需要使用双端队列
而如果一个元素已经是当前最小
根据 Dijstra 思想就无需再松弛了
所以本题的标记和判断 answer 都是对队首进行的
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;
}
BFS 2025/1/16的更多相关文章
- Word Ladder II leetcode java
题目: Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) ...
- [gym102798F]Skeleton Dynamization
考虑对于第$i$层$x$与第$i+1$层所对应的点$y$,点$p$在前$i$层中当且仅当$p$到$x$比$p$到$y$距离小 由此,考虑枚举第一层的一个点以及对应到第二层的边,通过bfs就可以确定第一 ...
- hdu1180奇怪的楼梯……bfs迷阵……wa该16二级,我太渣滓
#include<iostream> #include<queue> #include<cstring> using namespace std; int row, ...
- AOJ 0558 Cheese【BFS】
在H * W的地图上有N个奶酪工厂,分别生产硬度为1-N的奶酪.有一只吃货老鼠准备从老鼠洞出发吃遍每一个工厂的奶酪.老鼠有一个体力值,初始时为1,每吃一个工厂的奶酪体力值增加1(每个工厂只能吃一次), ...
- Codeforces Round #325 (Div. 2) D bfs
D. Phillip and Trains time limit per test 1 second memory limit per test 256 megabytes input standar ...
- codevs1004四子连棋[BFS 哈希]
1004 四子连棋 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗 ...
- POJ3083Catch That Cow[BFS]
Catch That Cow Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 77420 Accepted: 24457 ...
- POJ3967Ideal Path[反向bfs 层次图]
Ideal Path Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 1754 Accepted: 240 Descri ...
- hdu.1429.胜利大逃亡(续)(bfs + 0101011110)
胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- hdu.1067.Gap(bfs+hash)
Gap Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Subm ...
随机推荐
- 记录uniapp上传图片转base64
// 图片转base64 imageToBase64() { return new Promise((reslove, reject) => { uni.getFileSystemManager ...
- Solution Set - “潮汐守候终结放逐月圆”
目录 0.「NOI Simu.」游戏 1.「NOI Simu.」海盗 2.「集训队作业 2020-2021」「LOJ #3405」Gem Island 2 3.「UR #12」「UOJ #181」密码 ...
- Solution Set -「AGC 004~006」C~F
目录 「AGC 004C」AND Grid 「AGC 004D」Teleporter 「AGC 004E」Salvage Robots 「AGC 004F」Namori ^ 「AGC 005C」Tre ...
- 分布式文件系统KFS基础知识介绍
Kosmos distributed file system,简称KFS,是一个类GFS的分布式文件系统,被设计用于分布式的结构化存储.下面将对KFS的体系结构进行简单介绍,最后给出一个使用KFS C ...
- Apache Camel系列(4)----Akka Camel
Akka是一个高性能,高容错的的分布式框架,并且对Camel也提供了很好的支持,下面创建一个Akka Camel的demo,运行环境:CentOS7 + IntelliJ + JDK8.这个demo分 ...
- ThreeJs-14HTML混合3D渲染
一.css渲染器基本使用 使用场景:经常在一些3D物体左右还会跟随一些文字等,实际都是标签,应用场景非常广泛 先完成基本的3D,月球围绕地球转,这里就是给月球加了sin函数 然后现在就先创建一个标签体 ...
- 2025苹果春季发布会前瞻:新品迭出,Apple Intelligence国行版即将上线!
随着2025年的到来,苹果公司的春季发布会也渐行渐近.作为科技行业的领军企业,苹果每一次的新品发布都备受瞩目.本次春季发布会,苹果预计会带来一系列令人期待的新品,同时,国行Mac用户也将迎来一个重大更 ...
- HBase多租户分组
一.分组简介 RegionServer Group 通过对 RegionServer 进行分组,不同的 RegionServer 分到不同的组.每个组可以按需挂载不同的表,并且当组内的表发生异常后,R ...
- NFS服务器离线问题解决
NFS服务器离线问题解决 NFS服务器挂了会导致挂载的NFS客户端主机卡顿延迟,或者提示找不到文件 因为在执行一些命令的时候会自动去同步,用作同步的NFS服务端挂了,命令执行就会卡住 不过听说NFS还 ...
- C语言中的*和&符号
之前对*和&符号一直理解的比较浅显.只知道: *p好像表示的是一个指针: &p表示的是一个地址. 然而这次当遇到了下面这个情况的时候: int a = 10; int *b = &am ...