例题6-11 UVA297 Quadtrees(30行AC代码)

紫书刷题进行中,题解系列【GitHub|CSDN

例题6-11 UVA297 Quadtrees(30行AC代码)

题目大意

一个四叉树有三类节点,即父结点(P),黑色叶子(f),白色叶子(e)

现给出两个四叉树,求合并后黑色像素个数。

思路分析

输入为四叉树的先序序列,因此先序递归建树很容易,但关键在于如何合并两棵四叉树,计算黑色个数。

  • 尝试1:想同步层次/先序遍历两个四叉树,然后统计黑色个数,可惜两个树结构不完全一致,实现有些困难
  • 尝试2:将四叉树转换为原图片的二维矩阵,然后用标记的方式来统计黑色个数,正解

尝试2的思路很有启发性,对于复杂的树/图结构,可以转换为规则的一维/二维数组,便于做各种计算

因此可以不用真正建立四叉树(类似UVA839,UVA699,隐式建树),在转换为原图二维矩阵时,可借用哈希的思想(空间换时间),遇见黑色就将整个正方形中的小格子全标记为黑色,因此可以直接统计黑色个数。

注意点

  • 注意初始化数组为0
  • 注意使用引用变量
  • 可用技巧:四叉树转换为二维矩阵,隐式建树,空间换时间

AC代码(C++11,四叉树转二维矩阵,隐式建树,空间换时间)

#include<bits/stdc++.h>
using namespace std;
int T, cnt, img[1025][1025]={0}, idx;
// 根据s[idx]绘制左上角为(r,c),边长为w的正方形区域
void draw(string s, int& idx, int r, int c, int w) {
    if (idx >= s.size()) return;
    idx ++; // 先后移,注意引用
    if (s[idx-1] == 'p') { // 父结点,绘制4个子方格
        draw(s, idx, r, c+w/2, w/2);     // 1
        draw(s, idx, r, c, w/2);         // 2
        draw(s, idx, r+w/2, c, w/2);     // 3
        draw(s, idx, r+w/2, c+w/2, w/2); // 4
    }
    else if (s[idx-1] == 'f') { // 黑色才处理,白色默认0,不计数
        for (int i = r; i < r+w; i ++)  // 按最小方块标记上色
            for (int j = c; j < c+w; j ++) 
                if (img[i][j] == 0) {cnt++; img[i][j] = 1;} // 统计黑色个数,记得加标记
    }
}
int main() {
    scanf("%d", &T);
    string s1, s2;
    while (T --) {
        cin >>s1 >>s2;
        cnt=0; fill(img[0], img[0]+1025*1025, 0); // 初始化 
        draw(s1, idx=0, 0, 0, 32); // 1024=32*32个格子
        draw(s2, idx=0, 0, 0, 32); // 注意初始化idx=0
        printf("There are %d black pixels.\n", cnt);
    }
    return 0;
}
发布了128 篇原创文章 · 获赞 87 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_40738840/article/details/104321761