uva 112 Tree Summing
将原来的代码改了一个BUG即是存在负数后就AC了,但是时间不好,0.112
实际上本题就是由扩展前序序列来建树,然后遍历,算路径的题目,考查了二叉树的基本知识,很好
#include <stdio.h> #include <string.h> #include <stdlib.h> #define LEN sizeof(struct BTree) #define MAX 10010 char num[MAX][20],stack[MAX]; struct BTree { int data; struct BTree *lchild,*rchild; }*pre; int top,count,flag; void CUT() { int i=0,j=0; while( !(stack[i]>='0' && stack[i]<='9' || stack[i]=='-') ) i++; while(stack[i]>='0' && stack[i]<='9' || stack[i]=='-') { num[count][j++]=stack[i]; stack[i]='*'; i++; } num[count][j]='\0'; count++; } int move() { int i; for(i=top-1; i>=0; i--) if(stack[i]=='(') break; return i-1; } void input() { char ch; while(1) { ch=getchar(); if(ch==' ' || ch=='\n') continue; else if(ch=='(') { stack[++top]=ch; if(top>0 && ( stack[top-1]>='0' && stack[top-1]<='9' || stack[top-1]=='-')) CUT(); } else if(ch>='0' && ch<='9' || ch=='-') stack[++top]=ch; else { stack[++top]=ch; if(stack[top-1]=='(') { num[count][0]='#'; num[count][1]='\0'; count++; top-=2;} else top=move(); } if(top<0) {ch=getchar();return;} } } void create_BTree(struct BTree* *T,int *i) { int a; (*i)++; if(num[*i][0]=='#') (*T)=NULL; else { if(num[*i][0]!='-') sscanf(num[*i] , "%d" , &a); else { sscanf(num[*i]+1 , "%d" , &a); a=0-a; } (*T)=(struct BTree*)malloc(LEN); (*T)->data=a; create_BTree( &((*T)->lchild) , i); create_BTree( &((*T)->rchild) , i); } } void DFS_BTree(struct BTree *T) { if(!T) return ; printf("%d ",T->data); DFS_BTree(T->lchild); DFS_BTree(T->rchild); } void search(struct BTree *T , int key , int sum) { if(flag) return ; if(!T) { if(!pre->lchild && !pre->rchild && sum==key) flag=1; return ; } else { sum+=T->data; pre=T; search(T->lchild , key , sum); if(flag) return ; pre=T; search(T->rchild , key , sum); if(flag) return ; } } int main() { int i,key,sum; struct BTree *T; while(scanf("%d",&key)!=EOF) { top=-1; count=0; input(); // for(i=0; i<count; i++) printf("%s ",num[i]); printf("\n"); i=-1; create_BTree(&T,&i); // DFS_BTree(T); printf("\n"); if(!T) {printf("no\n"); continue;} flag=sum=0; pre=T; search(T,key,sum); if(flag) printf("yes\n"); else printf("no\n"); } return 0; }
仔细思考为什么建树的过程顺便计算结果就会WA,一定要把建树过程中同时遍历的程序写出来,因为这样时间将大大提高!
一直WA的原因是,左右孩子指针可能是野指针
经过总结和教训,指针在竞赛中是不适用的,所以尽量避免指针,即便是树这种数据结构也尽量用数组来实现
//悲剧的是时间没有提高多少!!!
#include <stdio.h> #include <string.h> #include <stdlib.h> #define LEN sizeof(struct BTree) #define MAX 100010 #define INF 1948723892 //用INF表示# char num[MAX][20],stack[MAX]; struct BTree { int data; struct BTree *lchild,*rchild; }*pre; //建树时记录前驱结点 int top,count,ok,len; int a[MAX]; void CUT() { int i=0,j=0; while( !(stack[i]>='0' && stack[i]<='9' || stack[i]=='-') ) i++; while(stack[i]>='0' && stack[i]<='9' || stack[i]=='-') { num[count][j++]=stack[i]; stack[i]='*'; i++; } num[count][j]='\0'; if(num[count][0]!='-') sscanf(num[count],"%d",&a[count]); else {sscanf(num[count]+1,"%d",&a[count]); a[count]=0-a[count];} count++; } int move() { int i; for(i=top-1; i>=0; i--) if(stack[i]=='(') break; return i-1; } void input() { char ch; while(1) { ch=getchar(); if(ch==' ' || ch=='\n') continue; else if(ch=='(') { stack[++top]=ch; if(top>0 && ( stack[top-1]>='0' && stack[top-1]<='9' || stack[top-1]=='-')) CUT(); } else if(ch>='0' && ch<='9' || ch=='-') stack[++top]=ch; else { stack[++top]=ch; if(stack[top-1]=='(') { num[count][0]='#'; num[count][1]='\0'; a[count]=INF; count++; top-=2;} else top=move(); } if(top<0) {ch=getchar();return;} } } void create_BTree(struct BTree* *T,int sum,int key,int mark) { len++; if(a[len]==INF) { (*T)=NULL; //先赋空 if(mark==2 && !(pre->lchild) && sum==key) ok=1; return ; //这个判断就是造成不断WA的原因,我们的目的其实是判断这个结点是不是叶子,抑或还只是缺了其中一个孩子,只有是叶子才能//赋值,判断叶子不能直接的 !pre->lchild && !pre->rchild 因为这两个可能是野指针! //试想一下扩展前序建树,其实和前序遍历的顺序是相同的,先是根结点,再左孩子,再右孩子,如果是叶子结点,那么左右孩子必//定为空,假设这个结点是左孩子,你能单纯地判断!pre->rchild吗?不能,因为这个时候的rchild是野指针,甚至都还没赋值,//你都不知道它还没有数据。有一个判断是一定准确的,那就是!如果这次的递归是用右边递归进来,而且是空结点,那么就只需要//判断前驱的左孩子是不是空,但问题是怎么知道这次的递归是用右边递归进来,那就是用mark来标记! //所以现在可以理解这个判断了吧 mark==2 && !(pre->lchild) && sum==key 是从右边递归进来的,而前驱 //的左孩子又是空,而sum又等于key,那就是这个结点了 } else { pre=(*T)=(struct BTree*)malloc(LEN); (*T)->data=a[len]; sum=sum+a[len]; pre=(*T); mark=1; create_BTree( &((*T)->lchild) , sum , key,mark); if(ok) return ; //在每个递归函数的出口加一个判断条件,如果已经找到答案就直接返回 pre=(*T); mark=2; create_BTree( &((*T)->rchild) , sum , key,mark); if(ok) return ; //在每个递归函数的出口加一个判断条件,如果已经找到答案就直接返回 } } int main() { int i,key,sum,mark; struct BTree *T; while(scanf("%d",&key)!=EOF) { top=-1; count=0; input(); len=-1; ok=sum=0; pre=NULL; mark=0; create_BTree(&T,sum,key,mark); if(ok==1) printf("yes\n"); else printf("no\n"); } return 0; }