原题
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);
}