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;
}

 

 

 

posted @ 2012-10-05 22:47  Titanium  阅读(221)  评论(0编辑  收藏  举报