UVa 112 树求和

题意:给定一个数字,以及一个描述树的字符序列,问存不存在一条从根到某叶子结点的路径使得其和等于那个数。难点在于如何处理字符序列,因为字符间可能有空格、换行等。

思路:本来想着用scanf的(后发现scanf貌似不能做),感觉太麻烦,想看网上有没有处理比较好的,一搜全是用C++的cin流的~  还是自己用C写了一下。用的getchar()。getchar()主要就是比较繁琐,需要一个一个字符比较,记得刚开始做字符串题目时比较喜欢用getchar(),有的用scanf就行的自己也喜欢用getchar();好久没用了,写之前觉得有些麻烦。。纠结了一下~ 还是不要嫌麻烦啊。。

这里还是避免了动态内存分配及释放这个易出错的东西,用一个先申请了的大Node数组anode,以及cnt记录已使用的anode的最大下标。同样,其中用栈来匹配时,入栈和出栈的都是相应结点在anode数组中的下标值。(已经用这个方法连续做几道题了,走火入魔了~)

处理树的录入的情况是,每读一个字符分三种情况:左括号、数字、右括号,及其他忽略。读入左括号时,若之前是在读数字(dsz为1),则数字结束,转为int型,初始化一个Node结点,在结点入栈前,若栈非空,则该结点是栈顶元素的左或右孩子(通过结构体的lv域判断左孩子是否已赋值)。读入数字时,很简单,主要注意负数的情况。读入右括号时,如果上一次是读的左括号(zkh为1),则说明读的是一个空括号,这样的情况下如果栈为空,则是读入了一个空树的特殊情形,若栈非空,则将栈顶元素的左或右孩子置为空,同样通过lv域来判断左右;如果读到的不是空括号,则对应栈顶元素的左右孩子均已赋值,出栈。

这样即可建树。不过可以发现和值在建树过程中即可计算,只要维护一个值,它是栈中元素的值之和即可。(程序中的he值)每到叶子结点时,通过与给定的值判断。另外还需注意的就是怎样跳出读取树描述符字节序列的这个while循环。这里用栈为空的时候,不过有几个特殊情况又需要fg变量进行标记,比如第一个为空格字符top本来就为0但不应跳出,比如读到空树时虽然没有数字入栈过但应该要跳出了所以置fg为1。

注意:值可为负数。(这个网搜的时候看别人提到,不知道自己会不会注意到)

本地调了几次,一次就AC了还是不错的。没有什么大错误,注意到一个数字读完后把计数置0就行了。UVa 365名还可以

Code:

#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#define MAXN 1000

typedef struct node
{
 int data;
 int left,right;
 bool lv;//左孩子是否已赋值      
 bool lnull;//左孩子是否为空 
}Node;

Node anode[MAXN];
int cnt=0;//已经用的Node的最大下标。位置0不用,代表空节点。 

int main()
{
 int sum=0;
 while(scanf("%d",&sum)==1)
 {//读一行 
  char c;
  bool zkh=0;
  char num[15]; int x=0;
  bool dsz=0;
  int stack[MAXN]; int top=0;//top始终指向栈顶元素,位置0不用,代表空栈 
  int he=0;//树的和值,当前栈内元素的和值。 
  bool flag=0;
  cnt=0;
  bool fg=0;
  while((c=getchar()))
  {//读树形式 
   if(c=='(')
   {
    if(dsz) 
    {
     num[x]='\0';
     x=0;     //注意这里一个数字输入结束后需置零下标位 
     int nmb=atoi(num);
     //构造新结点 
     anode[++cnt].data=nmb;
     anode[cnt].left=anode[cnt].right=0;
     anode[cnt].lv=0;
     anode[cnt].lnull=0;
     //入栈
     fg=1;//证明曾有数字入栈过 
     if(top)
     {//若栈非空,则当前元素是栈顶元素的左或右孩子 
      if(anode[stack[top]].lv==0) {anode[stack[top]].left=cnt; anode[stack[top]].lv=1;}
      else anode[stack[top]].right=cnt;
     }
     he=he+nmb;
     stack[++top]=cnt; 
    }     
    dsz=0; 
    zkh=1;   
   }
   else if(c=='-'||isdigit(c))
   {  
    num[x++]=c;
    dsz=1;
    zkh=0;    
   }
   else if(c==')')
   {
    if(zkh)//读到空括号()
    {
     if(top)
     {
      if(anode[stack[top]].lv==0) {anode[stack[top]].left=0; anode[stack[top]].lv=1; anode[stack[top]].lnull=1;}                    
      else {anode[stack[top]].right=0; if(anode[stack[top]].lnull&&he==sum) {flag=1; } }//若左右孩子均为空,则为叶子结点,则可比较和值。这里flag=1后还是不要break比较好,因为匹配栈到空时才退出循环,不然不好判断后面的输入字符到什么时候结束,不能用换行判断。 
     }
     else//读到空括号()且栈为空,则是空树。并把fg置1可跳出循环 
      { flag=0; fg=1;}
    }   
    else
    {//出栈 
     he=he-anode[stack[top]].data;
     top--;
    }
    dsz=0;
    zkh=0;
   }    
   if(fg&&(top==0)) break;                        
  }//while
  printf("%s\n",flag?"yes":"no");                      
 }
 return 0;   
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值