Flood Fill 算法主要用于查找连通块,用bfs来进行搜索
板子题:池塘计数
思路:遍历一遍,用bfs,记得判重。
#include <iostream>
#include <queue>
using namespace std;
const int N = 1021;
char ph[N][N];int n,m; bool st[N][N];
#define x first
#define y second
typedef pair<int,int> PII;
void bfs(int sx, int sy) {
queue<PII> q; q.push({sx,sy}); st[sx][sy] = true; // status数组判重
while(q.size()) { // 开始进行bfs
auto t = q.front(); q.pop(); // 出队
// 这里采用的是九宫格型,也可以用PII表示八个方向
for(int i = t.x-1; i <= t.x+1; ++i) {
for(int j = t.y-1; j <= t.y+1; ++j) {
if(i < 0 || i >= n || j < 0 || j >= m || st[i][j]) continue; // 越界
if(i == t.x && j = t.y) continue; // 等于中间值
if(ph[i][j] == '.') continue; // 不是'W'
q.push({i,j}); // 入队
st[i][j] = true;
}
}
}
}
int main()
{
cin>>n>>m;
for(int i = 0; i < n; ++i) {cin>>ph[i];} // input
int ans = 0;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
if(!st[i][j]) {
ans++; // 每当有一个有'W'时,就表明会有一个连通块的,即答案加一
bfs(i,j); // bfs
}
}
}
cout<<ans;
}
城堡问题
求最大连通块和连通块个数
思路:连通块个数与上一题类似,最大连通块 采用bfs时进行计数,找连通块的大小。
关于方向,用到位运算的相关知识。
#include <iostream>
#include <queue>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
// 方向不能乱,与要求数字表示的方向有关
PII pt[4] = {
{0,-1}, {-1,0}, {0,1}, {1,0}
};
const int N = 54;
int ph[N][N];
bool st[N][N];
int n,m,cnt,ret,temp;
// 返回值为连通块大小
int bfs(int sx, int sy) {
queue<PII> q; q.push({sx,sy});
st[sx][sy] = true;
int ans = 0;
while(q.size()) {
auto t = q.front(); q.pop();
ans++;
for(int i = 0; i < 4; ++i) {
int xx = t.x + pt[i].first, yy = t.y + pt[i].second;
if(xx < 0 || xx >= n || yy < 0 || yy >= m || st[xx][yy]) continue; // 越界 或者已经访问过
if(ph[t.x][t.y] >> i & 1) continue; // 是否有墙,有墙continue
q.push({xx,yy}); st[xx][yy] = true;
}
}
return ans;
}
int main()
{
cin>>n>>m;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) cin>>ph[i][j];
}
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
if(!st[i][j]) {
cnt++; // 连通块个数
ret = max(ret, bfs(i,j));
}
}
}
cout<<cnt<<"\n"<<ret;
}
山峰和山谷
思路:在一个九宫格内,它是最大的w,就表明,它一定是山峰,山谷亦然。在一个有更大的有更小的内,一定是山脉。
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 1021;
#define x first
#define y second
typedef pair<int,int> PII;
int n, ph[N][N]; bool st[N][N];
// 引用传递,因为要知道一个一个块内的多个值(thanhi,thanlo)
void bfs(int sx, int sy, bool &hi, bool &lo) {
queue<PII> q; q.push({sx,sy});st[sx][sy] = true;
while(q.size()) {
auto t = q.front(); q.pop();
for(int i = t.x - 1; i <= t.x + 1; ++i) {
for(int j = t.y - 1; j <= t.y + 1; ++j) {
if(i < 0 || i >= n || j < 0 || j >= n) continue; // 越界
// 与中间值不相同,表明存在大小关系比
if(ph[i][j] != ph[t.x][t.y]) {
// 比中间值大
if(ph[i][j] > ph[t.x][t.y]) hi = true;
// 比中间值小
else lo = true;
} else if(!st[i][j]) { // 相同,记得判重,因为可能再入队一个中间值,导致死循环。
q.push({i,j}); st[i][j] = true;
}
}
}
}
}
int main()
{
cin>>n;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) cin>>ph[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 thanhi = false, thanlo = false; // thanhi 是否有比ph[i][j] 大的值, thanlo 是否有比ph[i][j] 小的值
bfs(i,j,thanhi, thanlo);
if(!thanhi) peak++; // 没有 就是山峰
if(!thanlo) valley++; // 有就是山谷
}
}
}
cout<<peak<<" "<<valley;
}
今日算法学习总结:更系统的学了搜索,对递归有了更深的认识。关于递归,不要沉迷它的循环过程,这会让解题更加迷茫。