floodfill算法(洪水漫盖法、种子填充法) UVA572、HDU 5319、HDU 4574

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);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值