SOJ 1042

1042. Squadtrees

Constraints

Time Limit: 5 secs, Memory Limit: 32 MB

Description

Quadtrees are data structures used to store digital images. For our purposes, the images will be simple bitmaps, where every pixel is either a 1 (black) or a 0 (white). A quadtree representation of a bitmap is obtained as follows: first, associate the root node with the entire image. If the entire image is either all 1's or all 0's, then store that value in the node and you're done. Otherwise divide the region into four equal size quadrants, add four children to the root, and assign each child one of the four regions in the following order: the first child gets the upper left quadrant, the second the upper right, the third the lower left and the fourth the lower right. Then recursively apply the above rules to each of the children. For example, the 4x4 image on the left would be represented by the quadtree on the right:

Note that this procedure only works as stated if the image is a square and has a side length equal to a power of 2. For those images which do not meet those requirements, we pad the rows and columns with 0's (on the right and on the bottom, respectively) until we have a bitmap of the appropriate size. For example, a 5x13 image would be converted to a 16x16 bitmap (with the original image residing in the upper left portion, and the remainder of the image filled with 0's).

While quadtrees can result in a significant savings in space over the original image, even more savings can be achieved if we identify repeated subtrees. For example, in the tree above, the first and third subtrees of the root are identical, so we could replace the root of the third subtree with a reference to the first subtree, obtaining something that symbolically looks like the following:

We will call these compressed quadtrees super quadtrees, or squadtrees. For our purposes the use of a reference saves space only when the tree it replaces has height of at least 1. Thus, while we could replace 5 of the nodes which contain a B with references to the first node with a B, this would not in practice save any space in the compression. Using this rule, our squadtree contains only 12 nodes, as opposed to 17 in the original quadtree. Your job for this problem is to take a set of images and determine the number of nodes in both the resulting quadtrees and squadtrees.

Input

Input will consist of multiple problem instances. Each instance will start with a single line containing two integers n and m, indicating the number of rows and columns in the image. The maximum values for these integers is 128. The next n lines will each contain m characters representing the image to process. A black pixel will be represented by a '1', and a white pixel will be represented by a '0'. The input line 0 0 will terminate input and should not be processed.

Output

For each problem instance, output two integers separated by a single space. The first value is the number of nodes in the quadtree for the problem instance, and the second is the number of nodes in the squadtree.

Sample Input

4 4
1011
0111
1010
0111
6 7
1110111
1010101
0000000
0100010
1011101
1010101
0 0

Sample Output

17 12

61 24

利用递归的思想来求还是比较便捷的,依次求出树中每个节点的标号,然后通过判断一个节点的四个子节点的标号是否与其他的节点的相同来判断是否有相同子树,若有则将squadtree的值恢复到计算这棵子树之前的值。

// Problem#: 1042
// Submission#: 5065587
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{ 
    int child1,child2,child3,child4;//分别存储每个节点的四个子节点 
    node(){
    }
    node(int n1,int n2,int n3,int n4)
    {
        child1=n1;
        child2=n2;
        child3=n3;
        child4=n4;
    }
    bool equal(int n1,int n2,int n3,int n4)//用来判断两颗子树是否相等 
    {
        return child1==n1&&child2==n2&&child3==n3&&child4==n4;
    }
};
int pos;//用来记录每个子树在nodeset中的下标 
int row,col;//图片的行数和列数 
int image[130][130];//图片矩阵 
node nodeset[10000];//存储每个节点,也就是存储每个子树 
int tree,superTree;//tree保存quadtree的节点数,supertree保存squadtree的节点数 
void saveData()//读取图片数据 
{
    memset(image,0,sizeof(image));
    char c;
    for(int i=1;i<=row;++i)
    {
        for(int j=1;j<=col;++j)
        {
            cin>>c;
            image[i][j]=c-'0';
        }
    }
}
int findLabel(int x1,int y1,int x2,int y2)//用递归来求每个节点(或者说每个子树)在nodeset中的下标值,(x1,y1)是这一节点所表示的图片范围的左上角的点,(x2,y2)自然代表右下角 
{
    int temp=superTree;//先行将squadtree节点的数量保存 
    superTree++;//由于要求这一节点的下标,即说明了这一节点的存在,所以quadtree和squadtree都增加1 
    tree++;
    if(x1==x2&&y1==y2) return image[x1][y1];//这一条件说明递归的终止条件,若递归的图形面积为1,则返回那一点的像素值 
    int midx=(x2+x1)/2;//下面递归的求出四个子节点的下标值 
    int midy=(y2+y1)/2;
    int label1=findLabel(x1,y1,midx,midy);
    int label2=findLabel(x1,midy+1,midx,y2);
    int label3=findLabel(midx+1,y1,x2,midy);
    int label4=findLabel(midx+1,midy+1,x2,y2);
    if(label1==1&&label2==1&&label3==1&&label4==1)//若全部为1则要求的这一节点也为1,且没有子节点,所以要减去4 
    {
        superTree-=4;
        tree-=4;
        return 1;
    }
    if(label1==0&&label2==0&&label3==0&&label4==0)//都为0也同理 
    {
        superTree-=4;
        tree-=4;
        return 0;
    }
    for(int i=2;i<pos;++i)//在已存入nodeset的元素中寻找是否有与当前正在计算的子树相同的子树,若有则squadtree值恢复计算前的原值 
    {
        if(nodeset[i].equal(label1,label2,label3,label4))
        {
            superTree=temp;
            return i;
        }
    }
    nodeset[pos++]=node(label1,label2,label3,label4);//若没有找到相同子树,则将这一子树放入nodeset数组并返回下标号 
    return pos-1;
    
}
int main()
{
    while(cin>>row>>col&&row)
    {
        saveData();
        int sideLength=1;
        while(sideLength<max(row,col)) sideLength<<=1;//确定正方形图片的边长 
        pos=2;
        tree=0;
        superTree=0;
        findLabel(1,1,sideLength,sideLength);
        cout<<tree<<" "<<superTree<<endl;
    }
    return 0;
}                                 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值