**
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;
}