zoj1788——四分树---2022年4月18日

**

Quad Trees

**
Time Limit: 2000 msMemory Limit: 65536 KB

A binary image, such as the one shown in Figure 2(a), is usually represented as an array of binary entries, i.e., each entry of the array has value 0 or 1. Figure 2(b) shows the array that represents the binary image in Figure 2(a). To store the binary image of Figure 2(b), the so-called quad tree partition is usually used. For an N N array, N <= 512 and N = 2^i for some positive integer i, if the entries do not have the same value, then it is partitioned into four N/2 N/2 arrays, as shown in Figure 2©. If an N/2N/2 array does not have the same binary value, such as the upper right and lower right N/2N/2 arrays in Figure 2©, then we can divide it into four N/4N/4 arrays again. These N/4N/4 arrays in turn can also, if needed, be divided into four N/8
N/8 arrays, etc… The quad tree partition is completed when the whole array is partitioned into arrays of various size in which each array contains only one binary value. Figure 2© contains the arrays after the quad tree partition is completed.

在这里插入图片描述

24位的位图

在这里插入图片描述一个像素点反映了24位、
可以计算出图片的大小
除以8,转成字节。
除以两个1024是转成MB
在这里插入图片描述
像素点对应之后,数据量很大。所以需要压缩。

以ZOJ1067为例

在这里插入图片描述

就是把大区域变成小区域,保证小区域中的点全部都是同样的数字。

可以理解成颜色都一样就可以压缩成一块了,不用一个一个表示了。

细分区域,把区域分的尽可能小,保证已经是最小的或者只有一种数字的。

在这里插入图片描述

PR四分树,即点-区域四分树

在这里插入图片描述

如果数据点数大于1.
在这里插入图片描述

划分区域

在这里插入图片描述


根结点是整张照片 接下来的叶子结点是分一次(一次分四块)


在这里插入图片描述

自顶向下

也可以向上,先分,分成最小,再合并,如果一个区域都相同,则合并,删除其他结点。在这里插入图片描述

**

把上图四叉树编码结构象限图化成树

**
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

将两个方法一起用,先分到最小,然后再查进行合并。

(0,0)表示已经全部相同了, (0,1)是表示有全1, 1表示要分拆。 It means that its corresponding array is not necessary to decompose any more.(第一个0表示已经不用再继续细分了)In this case, the second value is 0 (respectively, 1) to indicate that all the entries in the array are 0 (respectively, 1)在这里插入图片描述

层次遍历树得到
(1)(0,0)(1)(0,1)(1)(0,0)(0,1)(1)(0,0)(0,0)(0,0)(0,1)(0,1)(0,0)(0,1)(0,0)(0,1).

建立四分树

1.存储结构
2. 如何生成一共具有全部结点的四分树。分拆到四分树,直到单位为1.
3. 合并的问题。
(1)先进行四个孩子判断相等的操作
(2) 如果四个孩子一样则合并,即剪枝,删除工作
(3)如果不一样,则需要改写双亲的值。

DFS基本算法
左上角(r,c )第r行第c列,(row, column)

遍历和合并算法

#include<iostream>
#include<queue>
using namespace std;
class quadtree
{
public:
	char value[3];//"00,01,1"
	quadtree* child[4];
	quadtree()
	{
		child[0] = child[1] = child[2] = child[3] = 0;
	}
	bool operator==(const quadtree& p) const
	{
		if (strcmp(value, "1") == 0 || strcmp(value, p.value) != 0)
		{
			return 0;//不能合并,两个值不同
		}
		else {
			return 1;
		}
	}
};
//判断两个孩子结点是否一样
const int maxn = 512 + 10;
char MAP[maxn][maxn];
quadtree* root;
//用深度优先的算法设定
quadtree* DFS(int r, int c, int len)//按区域
{
	int i=0;
	bool flag = 1;//判断四个孩子是否一样
	quadtree* temp = new quadtree;
	if (len == 1)//长度为1
	{
		temp->value[0] = '0';
		temp->value[1] = MAP[r][c];   //表示该位置的数字是什么
		temp->value[2] = 0; //结束标志
		return temp;
	}
	len /= 2;
	//四个角的位置
	temp->child[0] = DFS(r, c, len);
	temp->child[1] = DFS(r, c+len, len);
	temp->child[2] = DFS(r+len, c , len);
	temp->child[3] = DFS(r + len, c+len, len);
	//检查是否要合并
	//判断两个孩子的字符串是否一样。
	for (i = 1; i < 4; i++)//以0号为主,和1,2,3比较
	{
		if (!(*temp->child[0] == *temp->child[i]))
		{
			flag = 0;//有两个不一样
			break;
		}
	}
	//合并算法
	if (flag)
	{
		strcpy_s(temp->value, temp->child[0]->value);
		for (i = 0; i < 4; i++)
		{
			delete temp->child[i];
			temp->child[i] = 0;//孩子的指针置为空
		}
	}
	else//不需要合并则更改为混合型
	{
		strcpy_s(temp->value, "1");   //不合并填1   字符串
	}
	return temp;
}
//生成二进制串,就是给树一个遍历
//层次遍历
string levelorder(quadtree* root) 
{
	string s;       //将遍历到的结点的val值都存到s
	s = "";
	queue<quadtree *> qu;
	qu.push(root);
	quadtree* work = new quadtree;
	work = root;
	while (!qu.empty())
	{
		work = qu.front();
		qu.pop();
	    s+= work->value;
		//cout << work->value << endl;
		for (int i = 0; i < 4; i++)
		{
			if (work->child[i]->value != 0)
				qu.push(work->child[i]);
		}
	}
	return s;
}

这一步可以实现对树的遍历,还没有转换成16进制的数字。
在这里插入图片描述

转成16进制

全代码

#include<iostream>
#include<queue>
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<string.h> 
using namespace std;
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1);
	assert(str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;

		str1++;
		str2++;

	}
	if (*str1 > *str2)
		return 1;
	if (*str1 < *str2)
		return -1;
}
class quadtree
{
public:
	char value[3];         //"00,01,1"
	quadtree* child[4];
	quadtree()
	{
		child[0] = child[1] = child[2] = child[3] = 0;
	}
	bool operator==(const quadtree& p) const
	{
		if (my_strcmp(value, "1") == 0 || my_strcmp(value, p.value) != 0)
		{
			return 0;//不能合并,两个值不同
		}
		else {
			return 1;
		}
	}
};
//判断两个孩子结点是否一样
const int maxn = 512 + 10;
char MAP[maxn][maxn],str[5],ans[10000];//str用来存补16进制的0

//用深度优先的算法设定
quadtree* DFS(int r, int c, int len)//按区域
{
	int i=0;
	bool flag = 1;//判断四个孩子是否一样
	quadtree* temp = new quadtree;
	if (len == 1)//长度为1
	{
		temp->value[0] = '0';
		temp->value[1] = MAP[r][c];   //表示该位置的数字是什么
		temp->value[2] = 0; //结束标志
		return temp;
	}
	len /= 2;
	//四个角的位置
	temp->child[0] = DFS(r, c, len);
	temp->child[1] = DFS(r, c+len, len);
	temp->child[2] = DFS(r+len, c , len);
	temp->child[3] = DFS(r + len, c+len, len);
	//检查是否要合并
	//判断两个孩子的字符串是否一样。
	for (i = 1; i < 4; i++)//以0号为主,和1,2,3比较
	{
		if (!(*temp->child[0] == *temp->child[i]))
		{
			flag = 0;//有两个不一样
			break;
		}
	}
	//合并算法
	if (flag)
	{
		strcpy(temp->value, temp->child[0]->value);
		for (i = 0; i < 4; i++)
		{
			delete temp->child[i];
			temp->child[i] = 0;//孩子的指针置为空
		}
	}
	else//不需要合并则更改为混合型
	{
		strcpy(temp->value, "1");   //不合并填1   字符串
	}
	return temp;
}

//生成二进制串,就是给树一个遍历
//层次遍历
void function(char s[])
{
	int sum = 0;
	int i = 0;
	sum = (s[i] - '0') * 8 + (s[i + 1] - '0') * 4 + (s[i + 2] - '0') * 2 + (s[i + 3] - '0');
	if (sum >= 10)
	{
		switch (sum)
		{
		case 10: cout << 'A'; break;
		case 11: cout << 'B'; break;
		case 12: cout << 'C'; break;
		case 13: cout << 'D'; break;
		case 14: cout << 'E'; break;
		case 15: cout << 'F'; break;
		}
	}
	else
	{
		cout << sum;
	}
}
void levelorder(quadtree* root) 
{
	int i, slen = strlen(ans), jj = 0,pos=0,j=0;
	queue<quadtree *> qu;
	qu.push(root);
	quadtree* work = new quadtree;
	work = root;
	while (!qu.empty())
	{
		work = qu.front();
		qu.pop();
	     strcat(ans, work->value);
		//cout << work->value << endl;
		for (int i = 0; i < 4; i++)
		{
			if (work->child[i]->value != 0)
				qu.push(work->child[i]);
		}
		delete work;
	}
	slen = strlen(ans);

	//for (int i = 0; i < slen; i++)
	//	cout << ans[i];
	//cout << endl;
	if (slen%4!= 0)
	{
		for (i = 0; i < 4 - slen%4; i++)
		{
			str[i] = '0';
		}
		for (jj = i; jj < 4; jj++) str[jj] = ans[pos++];
		function(str);
	}
	for (i = pos; i < slen; i += 4)
	{
		for (j = 0; j < 4; j++)
		{
			str[j] = ans[i + j];//-‘0’表示把字符转成数字, '0'的ASC码值。
		}
		function(str);
	}
	cout << endl;
}

int main()
{
	int num=0,totalnum;
	cin >> totalnum;
	int count = 0;
	while (count < totalnum)
	{
		cin >> num;
		for (int i = 0; i < num; i++)
		{
			for (int j = 0; j < num; j++)
				cin >> MAP[i][j];
		}
		str[4] = 0;
		memset(ans, 0, sizeof(ans));
		quadtree* root = DFS(0, 0, num);//按区域
		levelorder(root);
		count++;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值