UVa297 (四分树 Quadtrees)

1、题目大意

  1. 题目链接UVa 297
  2. 给出结点值为 p, e, f 的两个严格四叉树(非叶结点的度为 4)的先序遍历序列,p 代表灰色,e 代表白色,f 代表黑色,将两个树对应的结点颜色相融合,求最终黑结点代表的像素个数。其中根结点代表像素数为1024个,其余每个结点代表的像素数为上一层结点的四分之一。

2、解题思路

  1. 根据先序序列就可以确定这个四叉树。因为本题中,严格四叉树的结点个数为 4n+1 个,如果结点值为 p,则该结点有子树;如果结点值为 e 或 f ,则该结点没有子树。
  2. 根据两个先序序列分别递归建树 tree1 和 tree2。
  3. 根据规则合并两个树,合并的结果存到 tree1 中。
  4. 遍历树 tree1 ,统计黑色结点代表的像素的个数。

3、参考代码

#include<iostream>
#include<string>

using namespace std;

struct node {
	char color;
	node *n1, *n2, *n3, *n4;
	node() :color('e'), n1(NULL), n2(NULL), n3(NULL), n4(NULL) {}
};

node* build(string& s, int& pos) {
	node* root = new node();
	root->color = s[pos];
	if (s[pos] == 'p') {
		pos++; root->n1 = build(s, pos); pos++; root->n2 = build(s, pos);
		pos++; root->n3 = build(s, pos); pos++; root->n4 = build(s, pos);
	}
	return root;
}

void merge(node* tree1, node* tree2) {
	if (tree2->color == 'f') {
		tree1->color = 'f';
		tree1->n1 = tree1->n2 = tree1->n3 = tree1->n4 = NULL;
	}
	else if (tree2->color == 'p' && tree1->color != 'f') {
		if (tree1->color == 'e') {
			tree1->n1 = tree2->n1; tree1->n2 = tree2->n2;
			tree1->n3 = tree2->n3; tree1->n4 = tree2->n4;
		}
		tree1->color = 'p';
		merge(tree1->n1, tree2->n1); merge(tree1->n2, tree2->n2);
		merge(tree1->n3, tree2->n3); merge(tree1->n4, tree2->n4);
	}
}

int cnt(node* tree, int level) {
	int sum = 0;
	if (tree == NULL) return 0;
	if (tree->color == 'f')
		sum += 1024 / level;
	sum += cnt(tree->n1, level * 4);
	sum += cnt(tree->n2, level * 4);
	sum += cnt(tree->n3, level * 4);
	sum += cnt(tree->n4, level * 4);
	return sum;
}


int main() {
	int n;
	cin >> n;
	while (n--) {
		string s;
		cin >> s;
		int pos = 0;
		node* tree1 = build(s, pos);
		cin >> s;
		pos = 0;
		node* tree2 = build(s, pos);
		merge(tree1, tree2);
		cout << "There are " << cnt(tree1, 1) << " black pixels." << endl;
	}
	return 0;
}

刘大爷书上的代码:

//刘大爷思路,直接模拟画出这个 32*32 的黑白图像的过程,边画边统计黑色结点的个数。
#include<iostream>
#include<string>
#include<cstring>

using namespace std;

int cnt;
int pic[32][32];

//把字符串“画”到 以(r, c)为左上顶点,宽度为 w 的图像 pic 中。
void draw(string& s, int& pos, int r, int c, int w) {
	if (s[pos] == 'p') {
		draw(s, ++pos, r + w / 2, c        , w / 2);
		draw(s, ++pos, r + w / 2, c + w / 2, w / 2);
		draw(s, ++pos, r        , c        , w / 2);
		draw(s, ++pos, r        , c + w / 2, w / 2);
	}
	else if (s[pos] == 'f') {
		for (int i = r; i < r + w; i++)
			for (int j = c; j < c + w; j++)
				if (pic[i][j] == 0) {
					pic[i][j] = 1;
					cnt++;
				}
	}
}

int main() {
	int n;
	cin >> n;
	while (n--) {
		memset(pic, 0, sizeof(pic));
		cnt = 0;
		string s;
		int pos = 0;
		cin >> s;
		draw(s, pos, 0, 0, 32);
		pos = 0; cin >> s;
		draw(s, pos, 0, 0, 32);
		cout << "There are " << cnt << " black pixels." << endl;
	}
	return 0;
}

4、解题感悟

  1. 刘大爷这个思路太妙了!直接模拟画出这个图像的过程,同时统计黑色像素的数目。思路很清晰,代码也很简单。
  2. 思考问题产生的过程,设置合理的数据结构,然后去模拟这个过程,进而解决这个问题。这可能就是所谓的面向对象编程思想吧。
  3. 多思考,多总结。

 

在C#中,我们可以创建一个简单的四叉树Quadtrees)数据结构。下面是一个基本的四叉树类的实现,包括节点添加、划分和查询等操作: ```csharp public class QuadTree<T> where T : IComparable<T> { private Node root; private int width, height; public QuadTree(int width, int height) { this.width = width; this.height = height; root = new Node(null); } // 节点类 private class Node { public T Data { get; set; } public Node[] Children { get; } = new Node[4]; public Node(T data) { Data = data; } public void Split() { if (Children.Any(n => n == null)) { for (int i = 0; i < 4; i++) { if (Children[i] == null) { var splitData = SplitData(Data); Children[i] = new Node(splitData[i]); } } } } // 数据划分策略,这里简单地按中心点将数据分为四个部分 private static T[] SplitData(T data) { return new[] { data / 2, data * 3 / 2, data - data / 2, data + data / 2 }; } } // 添加元素到 public void Insert(T value) { root.Split(); root.Data = value; InsertRecursively(root, value); } // 递归插入函数 private void InsertRecursively(Node node, T value) { if (value.CompareTo(node.Data) < 0) { if (node.Children[0] != null) InsertRecursively(node.Children[0], value); else node.Children[0] = new Node(value); } else if (value.CompareTo(node.Data) > 0) { if (node.Children[2] != null) InsertRecursively(node.Children[2], value); else node.Children[2] = new Node(value); } else return; // 如果值相等,不做处理 // 划分节点 node.Split(); } // 查询节点是否存在特定值 public bool Contains(T value) { return FindNode(root, value) != null; } // 递归查找节点 private Node FindNode(Node node, T value) { if (node == null || node.Data.Equals(value)) return node; for (int i = 0; i < 4; i++) { if (node.Children[i] != null && value.CompareTo(node.Children[i].Data) >= 0) return FindNode(node.Children[i], value); } return null; } } // 示例:创建并使用四叉树 QuadTree<int> quadTree = new QuadTree(10, 10); // 宽度和高度设为10 quadTree.Insert(50); bool contains = quadTree.Contains(30); // 返回false,因为30不在范围 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值