搜索
一、Flood Fill
flood fill算法通常是用于计处理连通块问题,由于其算法思路由一个连通块蔓延到周围的连通块,类似洪水蔓延,故得此名。
flood fill算法本质上还是bfs算法,将周围的连通块看作同一父结点的子结点,不难看出是一个树状结构。
模板如下:
//Flood Fill
bool vis[N][N];//标记一个点是否被搜索过
int mx[4]{0,-1,0,1},my[4]{-1,0,1,0};//偏移数组
int bfs(int i,int j)//从i,j开始搜
{
queue<pair<int,int>>q;
q.push({i,j});
vis[i][j] = 1;
while(!q.empty())
{
auto t = q.front();
p.pop();
for(int k = 0;k < 4;k++)//遍历周围的坐标,此处是四连通
{
int x = t.first + mx[k],y = t.second + my[k];
//写判断条件,满足判断条件则跳过
q.push({x,y});//将周围的连通块的坐标加入到队列中
}
}
//返回结果
}
//在主函数中遍历每个坐标
当然,队列可以通过手写的方式实现,具体参考我的这篇博客:单调栈与单调队列
如题:https://www.acwing.com/problem/content/1100/
城堡问题:
1 2 3 4 5 6 7 ############################# 1 # | # | # | | # #####---#####---#---#####---# 2 # # | # # # # # #---#####---#####---#####---# 3 # | | # # # # # #---#########---#####---#---# 4 # # | | | | # # ############################# (图 1) # = Wall | = No wall - = No wall 方向:上北下南左西右东。图1是一个城堡的地形图。
请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。
城堡被分割成 m∗n个方格区域,每个方格区域可以有0~4面墙。
注意:墙体厚度忽略不计。
输入格式
第一行包含两个整数 m 和 n,分别表示城堡南北方向的长度和东西方向的长度。
接下来 m 行,每行包含 n 个整数,每个整数都表示平面图对应位置的方块的墙的特征。
每个方块中墙的特征由数字 P 来描述,我们用1表示西墙,2表示北墙,4表示东墙,8表示南墙,P 为该方块包含墙的数字之和。
例如,如果一个方块的 P 为3,则 3 = 1 + 2,该方块包含西墙和北墙。
城堡的内墙被计算两次,方块(1,1)的南墙同时也是方块(2,1)的北墙。
输入的数据保证城堡至少有两个房间。
输出格式
共两行,第一行输出房间总数,第二行输出最大房间的面积(方块数)。
数据范围
1≤m,n≤50
0≤P≤15输入样例:
4 7 11 6 11 6 3 10 6 7 9 6 13 5 15 5 1 10 12 7 13 7 5 13 11 10 8 10 12 13输出样例:
5 9
我们将每个面积视为一个连通块,然后根据题目表述,将左上右下分别标记为0123,每个坐标的值的二进制表示墙是否存在。如3,四位二进制表示围殴0011,第一位为1,表示存在左边的墙,第二位为1,表示存在上边的墙。由此我们可以得到下面的代码
#include<iostream>
#include<queue>
using namespace std;
const int N = 55;
typedef pair<int, int> PII;
int g[N][N];
bool vis[N][N];
int n, m;
int max_area, room_num;
int mx[4]{ 0,-1,0,1 }, my[4]{ -1,0,1,0 };
int bfs(int i, int j)
{
queue<PII>q;
q.push({ i,j });
vis[i][j] = 1;
int area = 0;
while (!q.empty())
{
auto t = q.front();
q.pop();
area++;
for (int k = 0; k < 4; ++k)
{
int x = t.first + mx[k], y = t.second + my[k];
if (g[t.first][t.second] >> k & 1)continue;
if (vis[x][y])continue;
if (x < 0 || x >= n || y < 0 || y >= m)continue;
q.push({ x,y });
vis[x][y] = 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];
for(int i = 0;i < n;i++)
for(int j = 0;j < m;j++)
if (!vis[i][j])
{
max_area = max(max_area, bfs(i, j));
room_num++;
}
cout << room_num << endl << max_area << endl;
return 0;
}
二、最短路模型
最短路模型用于解常用来解决两点之间的最短路径问题,这里我们具体讨论一维数组和二维数组模拟的最短路问题。该类问题也是利用bfs算法进行的,搜索能够走到的点,计算到达目标点的最小层数。
模板如下:
int bfs()
{
queue<int>q;
q.push(a);//将起始点加入队列
//其他的初始化操作在这里进行
while(!q.empty())
{
int t = q.front();//取出队列头部的元素
q.pop();
//判断条件
q.push(b);//加入新的点
}
return c;//返回目标值
}
首先来看看一维数组的模拟,看题:https://www.acwing.com/problem/content/1102/
农夫知道一头牛的位置,想要抓住它。
农夫和牛都位于数轴上,农夫起始位于点 N,牛位于点 K。
农夫有两种移动方式:
- 从 X 移动到 X−1 或 X+1,每次移动花费一分钟
- 从 X 移动到 2∗X,每次移动花费一分钟
假设牛没有意识到农夫的行动,站在原地不动。
农夫最少要花多少时间才能抓住牛?
输入格式
共一行,包含两个整数N和K。
输出格式
输出一个整数,表示抓到牛所花费的最少时间。
数据范围
0≤N,K≤105
输入样例:
5 17输出样例:
4
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
typedef pair<int, int> PII;
int n, m;
int d[N];
int bfs()
{
memset(d, -1, sizeof d);
queue<int>q;
q.push(n);
d[n] = 0;
while (!q.empty())
{
int t = q.front();
q.pop();
if (t == m)return d[m];
int p;
p = t + 1;
if (p < N && d[p] == -1)
{
q.push(p);
d[p] = d[t] + 1;
}
p = t - 1;
if (p >= 0 && d[p] == -1)
{
q.push(p);
d[p] = d[t] + 1;
}
p = t << 1;
if (p < N && d[p] == -1)
{
q.push(p);
d[p] = d[t] + 1;
}
}
return d[m];
}
int main()
{
cin >> n >> m;
cout << bfs() << endl;
return 0;
}
然后是二维数组的模拟:https://www.acwing.com/problem/content/190/
农民 John 有很多牛,他想交易其中一头被 Don 称为 The Knight 的牛。
这头牛有一个独一无二的超能力,在农场里像 Knight 一样地跳(就是我们熟悉的象棋中马的走法)。
虽然这头神奇的牛不能跳到树上和石头上,但是它可以在牧场上随意跳,我们把牧场用一个 x,y 的坐标图来表示。
这头神奇的牛像其它牛一样喜欢吃草,给你一张地图,上面标注了 The Knight 的开始位置,树、灌木、石头以及其它障碍的位置,除此之外还有一捆草。
现在你的任务是,确定 The Knight 要想吃到草,至少需要跳多少次。
The Knight 的位置用
K来标记,障碍的位置用*来标记,草的位置用H来标记。这里有一个地图的例子:
11 | . . . . . . . . . . 10 | . . . . * . . . . . 9 | . . . . . . . . . . 8 | . . . * . * . . . . 7 | . . . . . . . * . . 6 | . . * . . * . . . H 5 | * . . . . . . . . . 4 | . . . * . . . * . . 3 | . K . . . . . . . . 2 | . . . * . . . . . * 1 | . . * . . . . * . . 0 ---------------------- 1 0 1 2 3 4 5 6 7 8 9 0The Knight 可以按照下图中的 A,B,C,D… 这条路径用 55 次跳到草的地方(有可能其它路线的长度也是 5):
11 | . . . . . . . . . . 10 | . . . . * . . . . . 9 | . . . . . . . . . . 8 | . . . * . * . . . . 7 | . . . . . . . * . . 6 | . . * . . * . . . F< 5 | * . B . . . . . . . 4 | . . . * C . . * E . 3 | .>A . . . . D . . . 2 | . . . * . . . . . * 1 | . . * . . . . * . . 0 ---------------------- 1 0 1 2 3 4 5 6 7 8 9 0注意: 数据保证一定有解。
输入格式
第 1 行: 两个数,表示农场的列数 CC 和行数 RR。
第 2…R+1 行: 每行一个由 C 个字符组成的字符串,共同描绘出牧场地图。
输出格式
一个整数,表示跳跃的最小次数。
数据范围
1≤R,C≤150
输入样例:

最低0.47元/天 解锁文章
1186

被折叠的 条评论
为什么被折叠?



