UVa OJ 112

1、这道题对我来说有很大难度,但我是完全靠自己做的,晚上6点开始,凌晨3点才做出来,花了这么长时间,而且是一次AC了这道通过率仅为20%的题目,其中的成就感简直无法用语言形容。

2、这道题考察树的建立以及宽度优先搜索。首先,题目给出的字符串是不规则的,要先整理成我们常见的形式才可以,具体用getchar,见代码。

3、其次,树的建立利用了栈,本题的难点是栈不可能既保存字符型的括号和结点型的结点,所以必须要两个栈。我想了一个办法,就是第一个栈用来保存“索引”,括号的话,就用整型的负极大值代替(防止和结点的取值搞混,因为没有结点会取这个值),至于结点,则再开辟一个栈,然后在原先的栈内本应保存结点的位置保存“结点在第二个栈中的下标”,即“索引”,是不是很像括号匹配问题?这个方案实现起来不是非常容易,具体见代码。

4、宽度优先搜索没什么说的,注意sum数组的清零,以及判断“judge是否变为true”的语句需要写两遍。

5、最后注意释放内存空间。

6、网上有神犇写了非常简洁的代码,甚至不用建树,但我认为还是按照常规思路来想较好,原因有二:第一,神犇的方法一般人想不到,尤其是比赛的时候;第二,本题考查的就是建树和bfs,应该借着这道题将知识好好温习一遍。

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#define Max 2147483647
using namespace std;
typedef struct Tnode
{
    int v;
    struct Tnode *left,*right;
    bool left_saw;
}Node;
bool flag,judge;
char ch;
char s[10000];
int stack[10000],ans,p,top,topc;
Node* chart[10000];
Node* root;
void init(void)
{
    int count1=0,count2=0;
    while(ch=getchar())
    {
        if(ch=='(')
        {
            count1++;
            flag=true;
            s[p++]='(';
        }
        if(ch=='-'||isdigit(ch))
        {
            s[p++]=ch;
        }
        if(ch==')')
        {
            count2++;
            s[p++]=')';
        }
        if(count1==count2&&flag)
            break;
    }
    return;
}
Node* newnode(void)
{
    Node*u=(Node*)malloc(sizeof(Node));
    if(u!=NULL)
    {
        u->left=u->right=NULL;
        u->left_saw=false;
    }
    return u;
}
void addnode(void)
{
    int i=0,num;
    Node*u=newnode();
    chart[0]=u;
    while(s[i])
    {
        if(s[i]=='(')
        {
            top++;
            stack[top]=-Max;
        }
        if(s[i]=='-'||isdigit(s[i]))
        {
            sscanf(&s[i],"%d",&num);
            u=newnode();
            u->v=num;
            topc++;top++;
            chart[topc]=u;stack[top]=topc;
            while(s[i]!='(') i++;
            i--;
        }
        if(s[i]==')')
        {
            if(stack[top]==-Max)
            {
                  if(chart[topc]->left_saw==false)
                      chart[topc]->left=NULL;
                  else
                      chart[topc]->right=NULL;
                  top--;
            }
            else
            {
                if(stack[top]>0)
                {
                if(chart[stack[top]-1]->left_saw==false)
                {
                   chart[stack[top]-1]->left=chart[stack[top]];
                   chart[stack[top]-1]->left_saw=true;
                }
                else
                   chart[stack[top]-1]->right=chart[stack[top]];
                top-=2;topc--;
                }
            }
        }
         i++;
    }
    root=chart[topc];
    return;
}
int bfs(void)
{
    int front=0,rear=1;
    judge=false;
    Node*q[10000];
    int sum[10000];
    memset(sum,0,sizeof(sum));
    q[0]=root;sum[0]=root->v;
    while(front<rear)
    {
        Node*u=q[front++];
        if(u->left!=NULL)
        {
             q[rear++]=u->left;
             sum[rear-1]=sum[front-1]+q[rear-1]->v;
        }
        if(sum[rear-1]==ans&&q[rear-1]->left==NULL&&q[rear-1]->right==NULL)
        {
            judge=true;
            break;
        }
        if(u->right!=NULL)
        {
             q[rear++]=u->right;
             sum[rear-1]=sum[front-1]+q[rear-1]->v;
        }
        if(sum[rear-1]==ans&&q[rear-1]->left==NULL&&q[rear-1]->right==NULL)
        {
            judge=true;
            break;
        }
    }
    if(!judge)
        printf("no\n");
    else
        printf("yes\n");
    return 0;
}
void remove_tree(Node*u)
{
    if(u->left==NULL&&u->right==NULL) {free(u);return;}
    if(u->left!=NULL)
    remove_tree(u->left);
    if(u->right!=NULL)
    remove_tree(u->right);
}
int main(void)
{
    while(scanf("%d",&ans)==1)
    {
        flag=false;p=0;top=topc=-1;
        memset(s,'\0',sizeof(s));
        memset(stack,0,sizeof(stack));
        memset(chart,NULL,sizeof(chart));
        init();
        if(s[0]=='('&&s[1]==')'&&s[2]=='\0')
           {
               printf("no\n");
               continue;
           }
        addnode();
        bfs();
        remove_tree(root);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值