floodfill
找到一个未被访问过的需要填充的点,以这个点为起点向四周扩展直至边界,填充次数即为连通块数
UVA572 Oil Deposits
题意
输入多个m行n列的矩阵,用0 0表示输入结束。
找出有多少块石油区域
用“@”代表石油
假如两个“@”在横,竖或对角线上相邻,就说它们位于同一区域
对于每个输入,输出一个数表示有几个石油区域。
分析
每次选择@向八个方向递归填充即可,将已经勘探的@变成*防止重复勘探
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 105;
char s[maxn][maxn];
int n, m;
void dfs(int i, int j) {
if (i<1 || i>n || j<1 || j>m) return;
if (s[i][j] == '*') return;
s[i][j] = '*';
dfs(i - 1, j);
dfs(i, j - 1);
dfs(i + 1, j);
dfs(i, j + 1);
dfs(i + 1, j + 1);
dfs(i - 1, j + 1);
dfs(i + 1, j - 1);
dfs(i - 1, j - 1);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
while (cin >> n >> m && n + m) {
for (int i = 1; i <= n; i++)
cin >> s[i] + 1;
int cnt = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (s[i][j] == '@')
cnt++, dfs(i, j);
cout << cnt << '\n';
}
}
HDU 5319 Painter
题意
给定一个要求上色的板子,每个格子都要要求的最终颜色
R 表 示红色,B 表示蓝色,G 表示绿色,. 表示不上色
现在有一支 红笔,每笔只能从左上到右下斜着画,长度不限
有一支蓝笔, 只能从右上到左下斜着画,长度不限
当蓝色和红色叠加的时候会变成绿色
问最少要画几笔才能完成上色
分析
绿色则表示既有红色又有蓝色
建立红色图和蓝色图,两图叠加即为最终图
分别对两个图,递归dfs即可
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 55;
int n, m;
char s[maxn][maxn];
bool r[maxn][maxn], b[maxn][maxn];
void dfs_r(int i, int j) {
if (i<1 || i>n || j<1 || j>m)return;
if (!r[i][j])return;
r[i][j] = false;
dfs_r(i + 1, j + 1);
dfs_r(i - 1, j - 1);
}
void dfs_b(int i, int j) {
if (i<1 || i>n || j<1 || j>m)return;
if (!b[i][j])return;
b[i][j] = false;
dfs_b(i - 1, j + 1);
dfs_b(i + 1, j - 1);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;
cin >> t;
while (t--) {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> (s[i] + 1);
m = strlen(s[1] + 1);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
switch (s[i][j])
{
case 'R':r[i][j] = true; break;
case 'B':b[i][j] = true; break;
case 'G':r[i][j] = b[i][j] = true; break;
case '.':break;
}
}
}
int cnt = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (r[i][j]) {
dfs_r(i, j);
cnt++;
}
if (b[i][j]) {
dfs_b(i, j);
cnt++;
}
}
}
cout << cnt << '\n';
}
}
ZOJ2922 Bombs
题意
给定一张方格图,图中某些格子里有一些炸弹,每个炸弹上标着 一个数字 p,每个炸弹能炸到 x 坐标和它相同,y 坐标大于它的 所有炸弹,以及左边 p 格的 y 坐标和它相同的炸弹
每个炸弹可以被手动点燃爆炸或者被别的炸弹炸到也会爆炸,问 所有炸弹爆炸的最小点燃炸弹数量
分析
**考虑炸弹的爆炸方向是向左和向上而非双向 **
从右下角开始 floodfill 即可
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#pragma warning (disable:4996)
const int maxn = 1005;
int n, m;
int a[maxn][maxn];
void dfs(int i, int j) {
if (!a[i][j]) return;
int k = a[i][j];
a[i][j] = 0;
for (int x = i - 1; x >= 1; x--)
dfs(x, j);
for (int y = j - 1; y >= 1 && y >= j - k; y--)
dfs(i, y);
}
int main() {
while (~scanf("%d%d", &n, &m)) {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &a[i][j]);
int cnt = 0;
for (int i = n; i >= 1; i--)
for (int j = m; j >= 1; j--)
if (a[i][j])
cnt++, dfs(i, j);
printf("%d\n", cnt);
}
}