TOJ Code the Tree AC 代码 以及题解

Code the Tree
Time Limit:  1.0 Seconds    Memory Limit:  65536K
Total Runs:  329    Accepted Runs:  101



A tree (i.e. a connected graph without cycles) with vertices numbered by the integers  1, 2, ..., n is given. The "Prufer" code of such a tree is built as follows: the leaf (a vertex that is incident to only one edge) with the minimal number is taken. This leaf, together with its incident edge is removed from the graph, while the number of the vertex that was adjacent to the leaf is written down. In the obtained graph, this procedure is repeated, until there is only one vertex left (which, by the way, always has number  n). The written down sequence of  n-1 numbers is called the Prufer code of the tree. 
Your task is, given a tree, to compute its Prufer code. The tree is denoted by a word of the language specified by the following grammar:
T ::= "(" N S ")"
S ::= " " T S
    | empty
N ::= number
That is, trees have parentheses around them, and a number denoting the identifier of the root vertex, followed by arbitrarily many (maybe none) subtrees separated by a single space character. As an example, take a look at the tree in the figure below which is denoted in the first line of the sample input. To generate further sample input, you may use your solution to Problem D. 
Note that, according to the definition given above, the root of a tree may be a leaf as well. It is only for the ease of denotation that we designate some vertex to be the root. Usually, what we are dealing here with is called an "unrooted tree".

Input Specification

The input contains several test cases. Each test case specifies a tree as described above on one line of the input file. Input is terminated by EOF. You may assume that 1≤n≤50.

Output Specification

For each test case generate a single line containing the Prufer code of the specified tree. Separate numbers by a single space. Do not print any spaces at the end of the line.

Sample Input

(2 (6 (7)) (3) (5 (1) (4)) (8))
(1 (2 (3)))
(6 (1 (4)) (2 (3) (5)))

Sample Output

5 2 5 2 6 2 8
2 3
2 1 6 2 6

一颗树(是一个没有环的连通的图),其节点是从1~N的。一颗树的Prufer编码如下所述:找到数字最小的叶子节点(一个节点仅与有一条边)。这个叶子节点连同与它相连

的边一起删除,同时把这个叶子节点的父母输出来。在剩余的节点和边构成的新树中,重复上述过程,知道树里只有一个节点为止。

例如第一组测试数据够成的树如下图所示:


重复这个步骤,最后得到答案:5 2 5 2 6 2 8

解决问题的关键是怎么将给出的括号表示法的字符串用图存储。

字符串分析,首先发现左括号没什么用处,因为遇到数字字符,就计算数字字符的值,并入栈,遇到右括号就让栈顶元素出栈,它就是新的栈顶元素的孩子。

到最后一个括号的时候,栈里面只剩一个数字了,直接POP出去即可。这是分析一下字符串中各部分的关系。

然后就牵涉怎么存图。

通过第二组测试数据,图为   1-2-3  可以看出一颗树的根可以是1也可以是3,因此说明并不知道那个叶子节点是树的根。

就像1和2。只能说1和2相关联。用vector存图,1对应的容器中放入2,2对应的容器中放入1。

接下来就到了求解阶段:

从第一个容器往第N个容器找,找到一个容量为1的容器(说明该顶点就是数值最小的叶子节点),则我要把容器中的数保存到答案数组,并将容器清空。

并到与它关联的节点的容器,把当前这个叶子节点清除掉。


其中要注意一个BUG,这个BUG导致WA了很多次,就是题目中可以输入(2)这样的INPUT 
这种情况下,Output为 一个空白行。要考虑边缘输入的情况!!!!!

AC代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#include <vector>

using namespace std;


vector <int> node[100];
vector <int> ::iterator it;
int N;

void CreateGraph(char str[]){
    stack <int> st;
    int j = 0;
    //int sum = 0 ;
    while( j < strlen(str)){
        if(str[j] == '(' || str[j] == ' ')
            j++;
        else if( str[j] >= '0' && str[j] <= '9' ){
            int num = 0;
            while(str[j] >= '0' && str[j] <= '9'){
                num = num * 10 + str[j] - '0';
                j++;
            }
            N = max(N,num);
            st.push(num);
        }else{
            j++;
            int temp = st.top();
            st.pop();
            if(st.empty())
                continue;
            int temp2 = st.top();
            node[temp2].push_back(temp);
            node[temp].push_back(temp2);
        }
    }
}

int ans[100];
void Solve(){
    int k = 0;
    int father, child;
    for( int j = 1; j < N ; j++){
        for( int i = 1; i <= N ; i++){
            if(node[i].size() == 1) ///最小数的叶子节点
            {
                ans[k++] = node[i][0];
                father = node[i][0];
                child = i;
                node[i].clear();
                break;
            }
        }
        ///在father节点删除child节点
        for( it = node[father].begin(); it != node[father].end(); it++ ){
            if(*it == child){
                node[father].erase(it);
                break;
            }
        }
    }
    printf("%d", ans[0]);
    for(int i = 1; i < k; i++)
        printf(" %d", ans[i]);
    printf("\n");
}

int main()
{

    char str[10000];
    while (gets(str)){
        if(strlen(str)<=3)
        {
            printf("\n");
            continue;
        }
        memset(node,0,sizeof(node));
        N = 1;
        CreateGraph(str);
        Solve();
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值