这道题最难的地方是怎么计算最后的结果,建树不难,就按照前序建树即可,DFS遍历也不难,要算出每棵是中黑色像素也不难,但问题是怎么确定最后的结果
//一下代码可以建树,可以DFS遍历,可以计算每棵树的黑点个数,但不能解出//本题,要做出一些改动
//提交通过,时间不错,在0.008到0.020之间
#include <stdio.h> #include <string.h> #include <stdlib.h> #define LEN sizeof(struct tree) int weight[7]={0,1024,256,64,16,4,1}; struct tree { char ch; int level,value; struct tree *child1,*child2,*child3,*child4; }; void create_tree(struct tree* *T,int level) { char ch; scanf("%c",&ch); if(ch=='e' || ch=='f') { (*T)=(struct tree*)malloc(LEN); (*T)->level=level++; (*T)->ch=ch; (*T)->child1=(*T)->child2=(*T)->child3=(*T)->child4=NULL; if(ch=='e') (*T)->value=0; else (*T)->value=1; return ; } else { (*T)=(struct tree*)malloc(LEN); (*T)->value=0; (*T)->level=level++; (*T)->ch=ch; create_tree( &((*T)->child1) , level); create_tree( &((*T)->child2) , level); create_tree( &((*T)->child3) , level); create_tree( &((*T)->child4) , level); } } void DFS(struct tree *T,int *sum1) { if(!T) return ; (*sum1)+=(T->value)*weight[T->level]; DFS(T->child1 , sum1); DFS(T->child2 , sum1); DFS(T->child3 , sum1); DFS(T->child4 , sum1); } int main() { int T,level,sum1,sum2; struct tree *T1,*T2; scanf("%d",&T); getchar(); //不可漏 while(T--) { level=1; create_tree(&T1,level); getchar(); //不可漏 sum1=0; DFS(T1,&sum1); printf("sum1=%d\n",sum1); level=1; create_tree(&T2,level); getchar(); //不可漏 sum2=0; DFS(T2,&sum2); printf("sum2=%d\n",sum2); printf("There are %d black pixels.\n",sum1+sum2); } return 0; }
保留原来的DFS,改个名字为dfs,另写一个DFS,dfs是用于递归一棵树并计算值,DFS是递归两棵树并作为判断并算值
#include <stdio.h> #include <string.h> #include <stdlib.h> #define LEN sizeof(struct tree) int weight[7]={0,1024,256,64,16,4,1}; //事先保存方便调用 struct tree { char ch; int level,value; struct tree *child1,*child2,*child3,*child4; }; void create_tree(struct tree* *T,int level) { char ch; scanf("%c",&ch); if(ch=='e' || ch=='f') { (*T)=(struct tree*)malloc(LEN); (*T)->level=level++; (*T)->ch=ch; (*T)->child1=(*T)->child2=(*T)->child3=(*T)->child4=NULL; if(ch=='e') (*T)->value=0; else (*T)->value=1; return ; } else { (*T)=(struct tree*)malloc(LEN); (*T)->value=0; (*T)->level=level++; (*T)->ch=ch; create_tree( &((*T)->child1) , level); create_tree( &((*T)->child2) , level); create_tree( &((*T)->child3) , level); create_tree( &((*T)->child4) , level); } } void dfs(struct tree *T , int *sum) //单独递归一棵树 { if(!T) return ; (*sum)+=weight[T->level]*T->value; dfs(T->child1 , sum); dfs(T->child2 , sum); dfs(T->child3 , sum); dfs(T->child4 , sum); } void DFS(struct tree *T1, struct tree *T2 , int *sum) { //同时递归两棵树,并判断哪颗棵树需要继续递归,如果两棵都要递归,那么就是调用其 //本身(DFS),如果只有其中一棵要递归那就是调用dfs if( T1->ch=='f' || T2->ch=='f') //两棵树当前在相同根结点处有至少有其中之一是黑点,那么不用再继续递归了,计算,然后返回,因为在这层会覆盖掉下面所有的点 { (*sum)+=weight[T1->level]; return ; } else //说明要么是白点,要么其中一棵,或者两棵都要继续分割 { if(T1->ch=='e' && T2->ch=='e') return ; //两个都是白点,下面都没有孩子,且不用计算,直接返回 else if(T1->ch=='p' && T2->ch=='p') //两个都还有下一代,那么同时递归两者,是用DFS { DFS(T1->child1,T2->child1,sum); DFS(T1->child2,T2->child2,sum); DFS(T1->child3,T2->child3,sum); DFS(T1->child4,T2->child4,sum); } else if(T1->ch=='p' && T2->ch=='e') //只有T1有下一代,T2没有,那么就去单独算T1的下一代有多少值 { dfs(T1->child1,sum); dfs(T1->child2,sum); dfs(T1->child3,sum); dfs(T1->child4,sum); } else //相反,只有T2有下一代,T1没有,只单独算T2的 { dfs(T2->child1,sum); dfs(T2->child2,sum); dfs(T2->child3,sum); dfs(T2->child4,sum); } } } int main() { int T,level,sum; struct tree *T1,*T2; scanf("%d",&T); getchar(); //不可漏 while(T--) { level=1; create_tree(&T1,level); getchar(); //不可漏 // sum=0; dfs(T1,&sum); printf("T1=%d\n",sum); //单凭dfs就可以算出一棵树的黑点数 level=1; create_tree(&T2,level); getchar(); //不可漏 // sum=0; dfs(T2,&sum); printf("T2=%d\n",sum); //单凭dfs就可以算出一棵树的黑点数 sum=0; DFS(T1,T2,&sum); printf("There are %d black pixels.\n",sum); } return 0; }
用数组来实现,这种思想是假设整棵树所有的结点都存在,(一共是有1365个点),一开始全部是白色,然后找到合适的条件就给相对应的点染色,然后将两个树的点进行或运算,或运算得到1的点就计数,然后输出合并后黑色的点的个数,然后要注意一点很关键的,最后进行或运算并不是全部的1365个点,而是最后1024个点,即下标342到1365的点(为方便计算下标从1开始),理清原理,一张图片是有1024个像素,其实是整棵树最底层的所有结点,用递归的思想去建树(实际上面没有建,只是不断递归找到需要染色的点的下标,找到了该点,就从该点开始,将其下属的所有子树的所有点都染成黑色,其中会染到一些非底层的点,但是没关系,因为我们在最后并不把这些点算在里面,这些非底层的点染色并不会浪费多少时间,因为递归是一直要这样下去的!)
//提交通过,时间也不错,0.012
#include <stdio.h> #include <string.h> #include <stdlib.h> #define TOTAL 1365 //最多结点1365,即下标最大1365 #define MAXSIZE 1400 int t1[MAXSIZE],t2[MAXSIZE]; //保存两棵树的全部结点,数组的元素从1到1365,这种思想是假设所有结点都是存在在,只是颜色要怎样确定而已 void dye(int R , int *t) //染色函数,将当前下标为R的结点染成黑色,并递归它的四个孩子染色 { if(R>TOTAL) return ; t[R]=1; dye(4*R-2,t); dye(4*R-1,t); dye(4*R,t); dye(4*R+1,t); } void create_tree(int R ,int *t) { char ch; if(R>TOTAL) return ; scanf("%c",&ch); if(ch=='e') return ; //当前这个结点是白色,那么其下属的所有结点都是白色,我们试图递归找出其所有的下属结点,并将它们都赋为0,但因为一开始清0了,//不用赋,所以跳过 else if(ch=='p') { create_tree(4*R-2,t); create_tree(4*R-1,t); create_tree(4*R,t); create_tree(4*R+1,t); } else dye(R,t); } int main() { int T,i; int level,mark,R,sum; //R是指当前结点在数组中的下标 scanf("%d",&T); getchar(); while(T--) { memset(t1,0,sizeof(t1)); memset(t2,0,sizeof(t2)); R=1; level=1; mark=0; create_tree(R,t1); getchar(); // for(i=1; i<=TOTAL; i++) printf("%3d",i); printf("\n"); // for(i=1; i<=TOTAL; i++) printf("%3d",t1[i]); printf("\n"); // for(sum=0,i=342; i<=TOTAL; i++) if(t1[i]) sum++; printf("t1=%d\n",sum); R=1; level=1; mark=0; create_tree(R,t2); getchar(); // for(i=1; i<=TOTAL; i++) printf("%3d",i); printf("\n"); // for(i=1; i<=TOTAL; i++) printf("%3d",t2[i]); printf("\n"); // for(sum=0,i=342; i<=TOTAL; i++) if(t2[i]) sum++; printf("t2=%d\n",sum); for(sum=0,i=342; i<=TOTAL; i++) if( t1[i]|t2[i] ) sum++; printf("There are %d black pixels.\n",sum); } return 0; }