views:

88

answers:

2

I have worked on UVA 10410 Tree Reconstruction several days. But I can't get the correct answer unitl now.

I have used an algorithm similar to the one which we always use to recovery a binary tree through the preorder traversal and the inorder traversal. But it can't work.

Can anyone help me? Thanks in advance.

A: 

I think I have the hang of it. I don't pretend it's efficient though.

Let's look at the first 3 digits of the BFS output:

4 3 5

We are in one of these situations:

  4         4
/  \   OR   |
3  5        3
x  x        |
            5
            x

What is the DFS for those 2 cases ?

  • 4 3 (3s-children) 5 (5s-children)
  • 4 3 5 (5s-children)

Quick note: if 3 does not have any child, then it's impossible to tell the two apart...

If we consider that the problem is decidable, then it's a matter of knowing if 5 follows 3 in the DFS representation.

  • If it does: it's a linear composition
  • If it does not then you go recursive: 4 has 2 children 3 and 5 and you can easily identify the subtree from the DFS representation. Then extract (preserving order) the BFS representation of these subtrees from the BFS you had and recurse :)

It seems fairly far from optimal, but I am a bit more worried about the undecidability.

Is there a constraint in expression-parse trees which states that once you have a node that only has one child none of the nodes in the subtree it represents can have more than one ?

Matthieu M.
I don't think decidability matters. The solution is supposed to find any tree that fits, there can be multiple answers. Also, the parse trees mentioned in the problem statement are just part of the story, the given traversals don't necessarily have to be those of a parse tree :). It can be any tree...
IVlad
A: 

"Note that when a parent was expanded the children were traversed in ascending order." This sentence is very important!

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

struct Node
{
    int value;
    Node *child; //left child
    Node *sibling; //right sibling

    Node(int v)
    {
        value = v;
        child = NULL;
        sibling = NULL;
    }
};

void BuildTree(Node *&root,vector<int> bfs,vector<int> dfs)
{
    root = NULL;
    if(bfs.size() == 1)
        root = new Node(bfs[0]);
    if(bfs.size() > 1)
    {
        root = new Node(bfs[0]);

        vector<int> candidate; //store candidate childs
        unsigned i;
        for(i = 1; i < bfs.size(); i++)
        {
            if(bfs[i] >= bfs[1])
                candidate.push_back(bfs[i]);
            else
                break;
        }

        //remove the non-candidate node
        int boundOfChild = candidate.size() - 1;
        for(i = candidate.size() - 1; i >= 1; i--)
        {
            vector<int>::iterator it1;
            vector<int>::iterator it2;
            it1 = find(dfs.begin(),dfs.end(),candidate[i]);
            it2 = find(dfs.begin(),dfs.end(),candidate[i - 1]);
            if(it1 < it2)
                boundOfChild = i;
        }
        if(boundOfChild != candidate.size() - 1)
            candidate.erase(candidate.begin() + boundOfChild,candidate.end());

        //get every child's bfs and dfs
        for(i = candidate.size(); i >= 1; i--)
        {
            vector<int>::iterator it1;
            vector<int>::iterator it2;
            if(i == candidate.size())
            {
                it1 = find(dfs.begin(),dfs.end(),candidate[i - 1]);
                it2 = dfs.end();
            }
            else
            {
                it1 = find(dfs.begin(),dfs.end(),candidate[i - 1]);
                it2 = find(dfs.begin(),dfs.end(),candidate[i]);
            }

            vector<int> tmp_dfs(it1,it2);
            vector<int> tmp_bfs;
            for(vector<int>::iterator it = bfs.begin(); it < bfs.end(); it++)
            {
                if(find(tmp_dfs.begin(),tmp_dfs.end(),*it) != tmp_dfs.end())
                    tmp_bfs.push_back(*it);
            }

            Node *tmp = root->child;
            BuildTree(root->child,tmp_bfs,tmp_dfs);
            root->child->sibling = tmp;
        }
    }
}

void PrintTree(Node *root)
{
    if(root == NULL)
        return;
    queue<Node*> Q;
    Q.push(root);
    while(!Q.empty())
    {
        Node *tmp = Q.front();
        Q.pop();
        cout << tmp->value << ": ";
        tmp = tmp->child;
        while(tmp)
        {
            cout << tmp->value << ",";
            Q.push(tmp);
            tmp = tmp->sibling;
        }
        cout << endl;
    }
}

//just test case
int BFS[] = {7,8,12,4,5,1,6,11,2,3,10,9,13,14};
int DFS[] = {7,8,4,5,2,3,12,1,6,10,14,11,9,13};

int main()
{
    vector<int> vBFS(BFS,BFS + sizeof(BFS) / sizeof(int));
    vector<int> vDFS(DFS,DFS + sizeof(DFS) / sizeof(int));

    Node *root = NULL;
    BuildTree(root,vBFS,vDFS);    
    PrintTree(root);

    return 0;
}
Vincent
So do you get accepted if you submit it?
IVlad
I haven't submitted it because the function PrintTree should be rewrited to meet the requirement - "in ascending order". But I think my algoritm should be right.
Vincent
The seems easy enough. Output the values to a temporary vector, sort that vector with `std::sort` and then print that vector. Not the most efficient, but you can worry about a possible TLE later.
IVlad