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;

}

 

 

 

你可能感兴趣的:(tree)