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;
}
时间: 2025-01-04 14:59:39

UVa 112 树求和的相关文章

UVA - 112 - Tree Summing (数的求和!栈的应用!)

UVA - 112 Tree Summing Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description  Tree Summing  Background LISP was one of the earliest high-level programming languages and, with FORTRAN, is one of the oldest

UVA 11426 gcd求和

UVA 11426 gcd求和 O - GCD - Extreme (II) Time Limit:10000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 11426 Description Problem JGCD Extreme (II)Input: Standard Input Output: Standard Output Given the value of N, y

uva 112 - Tree Summing

 Tree Summing  Background LISP was one of the earliest high-level programming languages and, with FORTRAN, is one of the oldest languages currently being used. Lists, which are the fundamental data structures in LISP, can easily be adapted to represe

poj3511--A Simple Problem with Integers(线段树求和)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 60441   Accepted: 18421 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

UVa 112 - Tree Summing(树的各路径求和,递归)

题目来源:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&page=show_problem&problem=48 Tree Summing  Background LISP was one of the earliest high-level programming languages and, with FORTRAN, is one of the olde

Uva 122 树的层次遍历 Trees on the level lrj白书 p149

是否可以把树上结点的编号,然后把二叉树存储在数组中呢?很遗憾如果结点在一条链上,那将是2^256个结点 所以需要采用动态结构 首先要读取结点,建立二叉树addnode()+read_input()承担这样的工作 然后遍历二叉树,读取结点编号输出bfs() 这道题有内存池应用的背景 附链接  http://blog.csdn.net/shawngucas/article/details/6574863 #include <cstdio> #include <cstring> #inc

UVa 11695 树的直径 Flight Planning

题意: 给出一棵树,删除一条边再添加一条边,求新树的最短的直径. 分析: 因为n比较小(n ≤ 2500),所以可以枚举删除的边,分裂成两棵树,然后有这么一个结论: 合并两棵树后得到的新树的最短直径为: 这两棵树一定是这样合并的,分别取两棵树直径的中点,然后将其连接起来.这样新树的直径才是最短的. 所以在找直径的同时还要记录下路径,方便找到中点. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm>

uva 1513(树状数组)

既然不能把树状数组的开头当作顶端,就把树状数组的结尾当作顶端,不断清空要拿走的片子,并更新结尾 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int maxn=100000+100; int ss[maxn*2],pos[maxn]; int t,m,n; void add(int x,int v

UVa 548 树(已知其中两种遍历, 还原树)

题意: 给出后序遍历和先序遍历, 还原一棵树, 然后求出从根节点到叶子的最小路劲和. 分析: 已知后序遍历, 那么后序的最后一个节点就是根节点, 然后在中序中找到这个节点, 它的左边就是左子树, 它的右边就是右子树, 然后递归下去. 技巧是不断的变动[r1,l1] [r2,l2] r1 l1是中序的区间 r2 l2是后序的区间 #include <bits/stdc++.h> using namespace std; const int maxn = 10000 + 10; int In_or