【hiho_week253】矩形分割

博客围绕hihocoder上矩形分割问题展开,给定由NxM个单位正方形组成的矩形,某些方格有分割线,求分割成的区域数目。解析指出这是求连通区域问题,可用DFS、BFS、并查集等算法,建图时将方格拆成基本三角形处理,作者还给出自己思路及他人并查集实现链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


原题

https://hihocoder.com/contest/hiho253

描述

小Hi有一块由NxM个单位正方形组成的矩形。现在小Ho在某些单位正方形上画了一道分割线,这条分割线或者是单位正方形的主对角线(用’‘表示),或者是副对角线(用’/'表示)。
现在小Hi想知道这些分割线把NxM的矩形分割成了多少块区域。
例如
/
/
就把2x2的矩形分成了5个区域。
//
\ /
/
把3x4的矩形分成了7个区域。

输入

第一包含两个整数N和M。(1 <= N, M <= 100)
以下N行每行包含M个字符。每个字符只可能是/\或者空格。

输出

分割成的区域数目。


我的思考

初看没有头绪,感觉是要跟左右斜杠的出现位置有关,正准备想呢,手贱点到解析了,然后。。就看了起来


解析

这道题本质上一道求连通区域的题目,可以用DFS/BFS/并查集等算法搞定。
不过这道题在建图上要稍微做一些处理。
我们可以把一个字符的占的区域看成由4个基本三角形组成,即一个方格被两条对角线分成的4个基本三角形,形如 X 的上下左右4个部分。
默认一个方格内上和右、右和下、下和左、左和上的两个三角形是连在一起的。同时上下两个相邻方格的下和上两个三角形、左右两个相邻方格的右和左两个三角形也是相连的。
而/ 和 \都会把一些基本三角隔开。
建图完成后求出图中连通块的数目即可。


看了解析之后的答案

看完解析,(因为并查集不熟悉)感觉拆成四个三角形比较难以用深度优先遍历实现,所以拆成3*3。

#include <iostream>
#include <vector>
#include <stack>
#include <cstdlib>
#include <cstdio>
#include <memory.h>

using namespace std;

int main(int argc, char** argv) {
		int n, m;
	scanf("%d %d", &n, &m);
	char temp;
	int all[300][300] = { 0 };
	int visited[300][300] = { 0 };
	memset(all, 0, sizeof(all));
	memset(visited, 0, sizeof(visited));
	
	for (int i = 0; i < n; i++) {
		getchar();
		for (int j = 0; j < m; j++) {
			scanf("%c", &temp);
			if (temp == '\\') {
				all[i * 3][j * 3] = all[i * 3 + 1][j * 3 + 1] = all[i * 3 + 2][j * 3 + 2] = 1;
			}
			else if (temp == '/') {
				all[i * 3][j * 3 + 2] = all[i * 3 + 1][j * 3 + 1] = all[i * 3 + 2][j * 3] = 1;
			}
		}
	}

	int num = 0;
	stack<vector<int>> S;

	for (int i2 = 0; i2 < n * 3; i2++) {
		for (int j2 = 0; j2 < m * 3; j2++) {
			if (all[i2][j2] == 0 && visited[i2][j2] == 0) {

				S.push({ i2, j2 });
				num++;
				// 处理栈中的点
				while (!S.empty()) {
					int i = S.top()[0];
					int j = S.top()[1];
					S.pop();
					// 标记访问过,并判断是否是边界点
					visited[i][j] = 1;

					// 扫描该像素点领域,将未访问的前景点入栈
					for (int ii = -1; ii <= 1; ii++) {
						for (int jj = -1; jj <= 1; jj++) {
							if (ii * jj == 0 && i + ii != -1 && i + ii != n * 3 && j + jj != -1 && j + jj != m * 3 && all[i + ii][j + jj] == 0 && visited[i + ii][j + jj] == 0) {
								S.push({ i + ii, j + jj });   // 种子点入栈
							}
						}
					}
				}
			}
		}
	}

	printf("%d\n", num);
}

PS.别人的并查集实现

https://www.cnblogs.com/dongling/p/6659512.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值