题目链接
https://vjudge.net/problem/UVA-297
题目大意
以用四分树来表示一个黑白图像,方法是用根结点表示整幅图像,然后把行列各分成两等分,按照图中的方式编号,从左到右对应4个子结点。如果某子结点对应的区域全黑或者全白,则直接用一个黑结点或者白结点表示,如果既有黑又有白,则用一个灰结点表示,并且为这个区域递归建树。给出两棵四分树的先序遍历,求二者合并之后(黑色部分合并)黑色像素的个数。p表示中间结点,f表示黑色(full),e表示白色(empty)。
解题思路
四分树比较特殊,只需要给出先序遍历就足以确定整棵树的结构。
这题我们同样可以不需要显式建树,可以使用隐式建树的办法,先序递归解析四分树,一边解析一边统计,开一个二维数组标记所有被涂黑的像素点,用以在合并第二棵树的时候对描黑的像素点判重。
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
#define endl '\n';
const int maxn = 2e3 + 10;
const int INF = 0x3fffffff;
const int mod = 1e9 + 7;
int buf[maxn][maxn], cnt;
// 将先序遍历序列s[p……]解析为以(r, c)为左上角,边长为w的区域
void draw(const string &s, int &p, int r, int c, int w) {
char ch = s[p++];
if (ch == 'p') { // 一个黑白像素混合区域,递归处理四个子区域
draw(s, p, r, c + w / 2, w / 2); // 1,右上
draw(s, p, r, c, w / 2); // 2,左上
draw(s, p, r + w / 2, c, w / 2); // 3,左下
draw(s, p, r + w / 2, c + w / 2, w / 2); // 4,右上
} else if (ch == 'f') { // 一个纯黑区域,涂黑并计数
for (int i = r; i < r + w; i++)
for (int j = c; j < c + w; j++)
if (buf[i][j] == 0) { // 这个点没有在之前被涂黑过
buf[i][j] = 1; // 涂黑
cnt++; // 统计
}
}
}
void solve() {
memset(buf, 0, sizeof buf);
cnt = 0;
string s;
// 先后解析两个四分树
for (int i = 0; i < 2; i++) {
cin >> s;
int p = 0;
draw(s, p, 0, 0, 32);
}
cout << "There are " << cnt << " black pixels.\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout << fixed;
cout.precision(18);
int Case = 1;
cin >> Case;
while (Case--)
solve();
return 0;
}