0
点赞
收藏
分享

微信扫一扫

[Acwing提高]搜索(BFS的Flood Fill和最短路模型)


[Acwing提高]搜索

BFS的Flood Fill和最短路模型

知识点

题目

扩展方式

类型

池塘计数

明确的二维地图

Flood Fill

城堡问题

地图转换,统计连通块数量

Flood Fill

山峰和山谷

搜索试探过程中记录一些东西,统计连通块内外分界处的关系

Flood Fill

迷宫问题

记录BFS最短路

BFS最短路

武士风度的牛

走马字

BFS最短路

抓住那头牛

一维最短路,估计范围

BFS最短路

题目

池塘计数

思路
裸的Flood Fill
代码

#include<bits/stdc++.h>
using namespace std;

#define x first
#define y second

typedef pair<int,int>PII;
const int N=1010,M=N*N;

int n,m;
char g[N][N];
PII q[M];
bool st[N][N];

void bfs(int sx,int sy)
{
int hh=0,tt=0;
q[0]={sx,sy};
st[sx][sy]=1;

while(hh<=tt)
{
PII t=q[hh++];

for(int i=t.x-1;i<=t.x+1;i++)
for(int j=t.y-1;j<=t.y+1;j++)
{
if(i==t.x&&j==t.y)continue;
if(i<0||i>=n||j<0||j>=m||g[i][j]=='.'||st[i][j])continue;

q[++tt]={i,j};
st[i][j]=1;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%s",g[i]);

int cnt=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(g[i][j]=='W'&&!st[i][j])
{
bfs(i,j);
cnt++;
}
printf("%d\n",cnt);
return 0;
}

城堡问题

思路
没有直接给地图张啥样,给了上下左右是否有墙的二进制信息,不用直接转换,bfs内部用下面代码看某个方向有没有墙即可

i>>k&1

统计连通块面积只要统计出队次数即可
代码

#include<bits/stdc++.h>

#define x first
#define y second

using namespace std;
const int N=55,M=N*N;
typedef pair<int,int> PII;

int n,m;
int g[N][N];
PII q[M];
bool st[N][N];

int bfs(int sx,int sy)
{
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int hh=0,tt=0;
q[0]={sx,sy};
int area=0;
st[sx][sy]=1;

while(hh<=tt)
{
PII t=q[hh++];
area++;

for(int i=0;i<4;i++)
{
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||a>=n||b<0||b>=m)continue;
if(st[a][b])continue;
if(g[t.x][t.y]>>i&1)continue;

q[++tt]={a,b};
st[a][b]=1;
}
}
return area;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>g[i][j];

int cnt=0,area=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(!st[i][j])
{
area=max(area,bfs(i,j));
cnt++;
}
cout<<cnt<<endl<<area<<endl;
return 0;
}

山峰和山谷

思路
统计边界信息,所以不能因为st访问过就直接continue。需要区分一下是连通块内部(st可以直接conitnue)还是连通块外部(不可以直接conitnue)
代码

#include<bits/stdc++.h>
#define x first
#define y second

using namespace std;
typedef pair<int,int>PII;

const int N=1e3+10,M=N*N;
PII q[M];
int g[N][N];
bool st[N][N];
int n;

int bfs(int sx,int sy)
{
int hh=0,tt=0;
int sf=1,sg=1;
q[0]={sx,sy};
st[sx][sy]=1;
while(hh<=tt)
{
PII t=q[hh++];
for(int i=t.x-1;i<=t.x+1;i++)
for(int j=t.y-1;j<=t.y+1;j++)
{
if(i==t.x&&j==t.y)continue;
if(i<0||j<0||i>=n||j>=n)continue;
if(g[i][j]>g[t.x][t.y])
{
sf=0;
continue;
}
if(g[i][j]<g[t.x][t.y])
{
sg=0;
continue;
}
if(g[i][j]==g[t.x][t.y]&&!st[i][j])
{
q[++tt]={i,j};
st[i][j]=1;
}
}
}
return sf+sg*2;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&g[i][j]);

int sf=0,sg=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(!st[i][j])
{
int flag=bfs(i,j);
if(flag==1)sf++;
else if(flag==2)sg++;
else if(flag==3)sf++,sg++;
}
printf("%d %d",sf,sg);
return 0;
}

yxc的代码

#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 1010, M = N * N;

int n;
int h[N][N];
PII q[M];
bool st[N][N];

void bfs(int sx, int sy, bool& has_higher, bool& has_lower)
{
int hh = 0, tt = 0;
q[0] = {sx, sy};
st[sx][sy] = true;

while (hh <= tt)
{
PII t = q[hh ++ ];

for (int i = t.x - 1; i <= t.x + 1; i ++ )
for (int j = t.y - 1; j <= t.y + 1; j ++ )
{
if (i == t.x && j == t.y) continue;
if (i < 0 || i >= n || j < 0 || j >= n) continue;
if (h[i][j] != h[t.x][t.y]) // 山脉的边界
{
if (h[i][j] > h[t.x][t.y]) has_higher = true;
else has_lower = true;
}
else if (!st[i][j])
{
q[ ++ tt] = {i, j};
st[i][j] = true;
}
}
}
}

int main()
{
scanf("%d", &n);

for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
scanf("%d", &h[i][j]);

int peak = 0, valley = 0;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
if (!st[i][j])
{
bool has_higher = false, has_lower = false;
bfs(i, j, has_higher, has_lower);
if (!has_higher) peak ++ ;
if (!has_lower) valley ++ ;
}

printf("%d %d\n", peak, valley);

return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/130795/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

迷宫问题

思路
输出最短路方案
把st数组改为PII类型的pre数组记录转移,为了方便输出避免逆序,我们从终点开始BFS到起点,pre数组同时起标记和记录转移的作用
代码

#include<bits/stdc++.h>
#define x first
#define y second

using namespace std;

typedef pair<int,int>PII;
const int N=1e3+10,M=N*N;
int n;
PII q[M];
int g[N][N];
PII pre[N][N];


void bfs(int sx,int sy)
{
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
q[0]={sx,sy};
int hh=0,tt=0;
memset(pre,-1,sizeof pre);
pre[sx][sy]={0,0};
while(hh<=tt)
{
PII t=q[hh++];
for(int i=0;i<4;i++)
{
int a=t.x+dx[i];
int b=t.y+dy[i];
if(a<0||b<0||a>=n||b>=n||pre[a][b].x!=-1||g[a][b])continue;

q[++tt]={a,b};
pre[a][b]=t;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&g[i][j]);

bfs(n-1,n-1);//逆序搜索
PII end(0,0);
while(1)
{
printf("%d %d\n",end.x,end.y);
if(end.x==n-1&&end.y==n-1)break;
end=pre[end.x][end.y];
}
return 0;
}

武士风度的牛

思路
比较裸的BFS求最短路,会写移动数组即可
其实这个BFS求最短路可以看成堆优化版本的dijkstra的特殊情况版本(优先队列边权不同有不一样的优先级,这个边权都相同那就普通队列嘛)
代码(结构体写法)

#include<bits/stdc++.h>
using namespace std;
const int N=200,M=N*N;
char g[N][N];
bool st[N][N];
struct Node
{
int x,y,s;
}q[M];
int n,m,cnt;
int sx,sy,ex,ey;
Node bfs(int sx,int sy)
{
int hh=0,tt=0;
int dx[]={2,2,1,-1,1,-1,-2,-2};
int dy[]={-1,1,-2,-2,2,2,-1,1};
q[0]={sx,sy,1};
st[sx][sy]=1;
while(hh<=tt)
{
Node t=q[hh++];
for(int i=0;i<8;i++)
{
int a=t.x+dx[i],b=t.y+dy[i];
if(a<0||b<0||a>=n||b>=m||g[a][b]=='*'||st[a][b])continue;
q[++tt]={a,b,t.s+1};
st[a][b]=1;
if(a==ex&&b==ey)return t;
}
}
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>g[i][j];
if(g[i][j]=='K')sx=i,sy=j;
if(g[i][j]=='H')ex=i,ey=j;
}
cout<<bfs(sx,sy).s;
return 0;
}

yxc的代码(开数组的写法,后期写图论最短路可能习惯写)

#include <cstring>
#include <iostream>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 155, M = N * N;

int n, m;
char g[N][N];
PII q[M];
int dist[N][N];

int bfs()
{
int dx[] = {-2, -1, 1, 2, 2, 1, -1, -2};
int dy[] = {1, 2, 2, 1, -1, -2, -2, -1};

int sx, sy;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
if (g[i][j] == 'K')
sx = i, sy = j;

int hh = 0, tt = 0;
q[0] = {sx, sy};

memset(dist, -1, sizeof dist);//初始化
dist[sx][sy] = 0;

while (hh <= tt)
{
auto t = q[hh ++ ];

for (int i = 0; i < 8; i ++ )
{
int a = t.x + dx[i], b = t.y + dy[i];
if (a < 0 || a >= n || b < 0 || b >= m) continue;
if (g[a][b] == '*') continue;
if (dist[a][b] != -1) continue;
if (g[a][b] == 'H') return dist[t.x][t.y] + 1;

dist[a][b] = dist[t.x][t.y] + 1;
q[ ++ tt] = {a, b};
}
}

return -1;
}

int main()
{
cin >> m >> n;

for (int i = 0; i < n; i ++ ) cin >> g[i];

cout << bfs() << endl;

return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/130867/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

抓住那头牛

思路
边权相同所以可以用BFS求最短路,但是要处理一下范围防止出现无限的情况,估计范围为0~2*K

代码

#include<bits/stdc++.h>
using namespace std;

const int N=2e5+10;
int n,k;
int q[N];
int dist[N];//同时起到记录步数和标记是否访问过的作用

int bfs()
{
memset(dist,-1,sizeof dist);
dist[n]=0;
q[0]=n;
int hh=0,tt=0;
while(hh<=tt)
{
int t=q[hh++];
if(t==k)return dist[k];
if(t+1<N&&dist[t+1]==-1)
{
dist[t+1]=dist[t]+1;
q[++tt]=t+1;
}
if(t-1>=0&&dist[t-1]==-1)
{
dist[t-1]=dist[t]+1;
q[++tt]=t-1;
}
if(t*2<N&& dist[2*t]==-1)
{
dist[2*t]=dist[t]+1;
q[++tt]=2*t;
}
}
return -1;
}

int main()
{
scanf("%d%d",&n,&k);
printf("%d\n",bfs());
}


举报

相关推荐

0 条评论