题意:每张图片可分为1024个像素,用四叉树结构表示。最高高度5。每个像素或黑或白,即或1或0.现将两个这样的图,即树合并,同一位置的像素其中一张是黑,则结果是黑色。求最终合并的图中有多少黑像素。
思路:最直接的思路就是构建四叉树,然后对两个四叉树进行合并对比吧。把四叉树建好之后,发现不会合并了,想了下,很复杂。网搜的有对比四叉树以及填充数组这两种思路。其中有一个直接没有建树、填数组就行了,没仔细看。最终我在四叉树建好之后,让叶子结点或者说 f 结点来填数组,两棵树各填一次,最终统计1的个数。
建树的时候是利用栈,只将 p 结点入栈,给栈顶元素赋满四个孩子后出栈。 后面处理是用深搜,递归实现。只不过在遇到 f 结点时进行填数组。
建树方面还是比较顺利的,就是后面处理纠结了很长时间,察觉到“对每个结点填数组可以递归地设定填的起始位置和宽度”后还是很容易写的。没什么小错误,就是最后输出的地方输出的是句子不是单个数字,WA了一次。。 要学会用递归
方法一 - Code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXN 100
typedef struct qnode
{
int data;
struct qnode *y,*e,*sa,*si;
}Qnode;
void count();
void dfs(Qnode *r,int fw,int st);
void fill(int st,int fw);
Qnode* build();
Qnode* newnode();
void remove_tree(Qnode *root);
int pix[1024];
int main()
{
int n=0;
scanf("%d",&n);
getchar();
while(n-->0)
{
Qnode* root1=build();
Qnode* root2=build();
memset(pix,0,sizeof(pix));
dfs(root1,1024,0);
dfs(root2,1024,0);
count();
remove_tree(root1);
remove_tree(root2);
}
return 0;
}
void count()
{
int cnt=0;
for(int i=0;i<1024;++i)
if(pix[i]) cnt++;
printf("There are %d black pixels.\n",cnt);
}
void dfs(Qnode *r,int fw,int st)
{//st为数组应填的起始下标,fw为要填充的宽度或范围。
if(r==NULL) return ;
if(r->data==1) fill(st,fw);
else if(r->data==2)
{
dfs(r->y,fw>>2,st);
dfs(r->e,fw>>2,st+(fw>>2));//加号的优先级比右移高。另外,除以4是右移2不是右移4。。。
dfs(r->sa,fw>>2,st+2*(fw>>2));
dfs(r->si,fw>>2,st+3*(fw>>2));
}
}
void fill(int st,int fw)
{//st为数组应填的起始下标,fw为要填充的宽度或范围。
for(int i=0;i<fw;++i)
pix[st+i]=1;
//printf("st:%d~%d\n",st,st+fw-1);
}
Qnode* build()
{
char c;
Qnode* stack[MAXN]; int top=0;
int flag=0;
Qnode *root=NULL;
while((c=getchar())&&c!='\n')
{
Qnode *u=newnode();
if(top)
{
Qnode *t=stack[top];
if(t->y==NULL) t->y=u;
else if(t->e==NULL) t->e=u;
else if(t->sa==NULL) t->sa=u;
else if(t->si==NULL)
{//有四个孩子,出栈
t->si=u;
top--;
}
}
if(c=='p')
{//入栈
u->data=2;
stack[++top]=u;
}
else if(c=='e')
{
u->data=0;
}
else if(c=='f')
{
u->data=1;
}
if(!flag) {root=u; flag=1;}
}
return root;
}
Qnode* newnode()
{
Qnode* u=(Qnode*)malloc(sizeof(Qnode));
if(u!=NULL)
{
u->data=-1;
u->y=u->e=u->sa=u->si=NULL;
}
return u;
}
void remove_tree(Qnode *root)
{
if(root!=NULL)
{
remove_tree(root->y);
remove_tree(root->e);
remove_tree(root->sa);
remove_tree(root->si);
free(root);
}
}
方法二 - Code:
可以发现在递归填数组时是可以建树的,所以可以将两个过程合并。用递归法建树,并在建树过程中填数组。AC后时间比上一个稍长一点,不知道是递归的原因还是每次测试数据不同的原因。。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXN 100
typedef struct qnode
{
char data;
struct qnode *y,*e,*sa,*si;
}Qnode;
void count();
Qnode* dfs(int st,int fw);
void fill(int st,int fw);
Qnode* newnode();
void remove_tree(Qnode *root);
int pix[1024];
int main()
{
int n=0;
scanf("%d",&n);
getchar();
while(n-->0)
{
memset(pix,0,sizeof(pix));
Qnode* root1=dfs(0,1024);
getchar();
Qnode* root2=dfs(0,1024);
getchar();
count();
remove_tree(root1);
remove_tree(root2);
}
return 0;
}
void count()
{
int cnt=0;
for(int i=0;i<1024;++i)
if(pix[i]) cnt++;
printf("There are %d black pixels.\n",cnt);
}
Qnode* dfs(int st,int fw)
{
char c=getchar();
Qnode* u=newnode();
u->data=c;
if(c=='e') return u;
if(c=='f')
{
fill(st,fw);
return u;
}
if(c=='p')
{
u->y=dfs(st,fw>>2);
u->e=dfs(st+(fw>>2),fw>>2);
u->sa=dfs(st+2*(fw>>2),fw>>2);
u->si=dfs(st+3*(fw>>2),fw>>2);
return u;
}
}
void fill(int st,int fw)
{//st为数组应填的起始下标,fw为要填充的宽度或范围。
for(int i=0;i<fw;++i)
pix[st+i]=1;
//printf("st:%d~%d\n",st,st+fw-1);
}
Qnode* newnode()
{
Qnode* u=(Qnode*)malloc(sizeof(Qnode));
if(u!=NULL)
{
u->data=-1;
u->y=u->e=u->sa=u->si=NULL;
}
return u;
}
void remove_tree(Qnode *root)
{
if(root!=NULL)
{
remove_tree(root->y);
remove_tree(root->e);
remove_tree(root->sa);
remove_tree(root->si);
free(root);
}
}