ZOJ-1097-Code the Tree

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1097

题目大意:

树(即无环图)的顶点,用整数1,2……,n编号。Prufer码是按如下步骤构造的树:找到编号最小的叶节点,将该叶节点及其相连的那条变,从图中删除的同时,记下与它相连的那个结点的编号。重复上面的步骤,知道剩下最后一个结点(这个数就是n)。写下来的n-1个数的序列,就是该树的Prufer码。

编程任务:根据输入的树计算该树的Prufer码。

树的语法规则如体重描述

就是说,树的周围有括号。第一个树是根节点的编号,后面更有任意个子树(也可能没有),中间有一个空格。

算法分析:

1、数据结构

需要将每个结点的相邻节点建立对应关系,使用vector()和set()很容易实现,操作也比较方便 :vector<set<int> >

2、实现Prufer编码

使用优先队列处理,对于一个结点,当只有一个结点与其相邻时,就是叶子节点,首先将所有叶子结点放入优先队列中,选出编号最小的叶节点,输入其相邻结点,同时删除次叶节点,并在处理过程中将成为叶节点的结点放入优先队列中。

Priority_queue<int,vector<int> ,greater<int> >leafs;

3、对于本题主要在于建立各个结点间的对应关系,我采用的是非递归的方法建立,也可用递归实现

View Code
#include<iostream>

#include<stack>

#include<vector>

#include<queue>

#include<set>

#include<cstring>

#include<cstdio>

using namespace std;



char str[300];



void init(vector<set<int> > &adj)

{

    int x,y,n,len=strlen(str),pos=0;    

    stack<int>num;

    while(pos<len-1)

    {

        if(str[pos]=='(')    //左括号,标号进栈

        {

            sscanf(str+pos+1,"%d%n",&x,&n);

            pos+=n+1;    //pos移动到数字后面一位

            num.push(x);

        }

        else if(str[pos]==')')    //右括号,读取栈顶两个元素,

        {

            y = num.top();    num.pop();

            x = num.top();

            adj[x].insert(y);    //结点的相邻是对称的

            adj[y].insert(x);

            pos++;    //pos移位

        }

        else if(str[pos]==' ')    pos++;    //空格,向后移动

    }

}



int main()

{

    int x,y,i,sum;

    while(gets(str))

    {

        vector<set<int> >adj(100,set<int>());

        x = y = 1;

        init(adj);

        priority_queue<int,vector<int>,greater<int> >leafs;

        sum=0;

        for(i=1;adj[i].size();i++)

        {

            sum++;        //统计结点个数

            if(adj[i].size()==1)    //叶子节点进入优先队列

                leafs.push(i);

        }

        for(i=1;i<sum;i++)    //处理优先队列

        {

            x = leafs.top();    leafs.pop();

            y =  *(adj[x].begin());

            adj[x].erase(y);    //删除关系

            adj[y].erase(x);

            if(adj[y].size()==1)    //如果y也成为叶子节点,进入优先队列

                leafs.push(y);

            if(i>1)    cout<<' ';

            cout<<y;    //

        }

        cout<<endl;

    }

    return 0;

}
View Code
#include <iostream>

#include <queue>

#include <set>

#include <vector>

using namespace std;



void parse (vector<set<int> > &adj, unsigned int p = 0)

{                    //采用递归来进行数据与结点编号的转换

    unsigned int x;

    cin >> ws >> x;    //cin>>ws 忽略空格,读取编号

    if (p)    //相邻对称,p为真,表示前面读取的是结点编号

    {

        adj[p].insert (x);

        adj[x].insert (p);

    }

    while (true)

    {

        char ch;

        cin >> ws >> ch;    //读取括号

        if (ch == ')') break;    //如果是‘)’,递归返回

        parse (adj, x);    //否则是‘(’,递归调用

    }

    return;

}



int main ()

{

    char ch;

    while (cin >> ws >> ch)

    {

        vector<set<int> > adj (1024, set<int>());

        parse (adj);

        priority_queue< int, vector<int>, greater<int> > leafs;

        int n = 0;

        for (unsigned int i=0; i<adj.size(); i++)

            if (adj[i].size())

            {

                n++;

                if (adj[i].size() == 1)

                    leafs.push (i);

            }

        for (int k=1; k<n; k++)

        {

            unsigned int x = leafs.top();

            leafs.pop();

            unsigned int p = *(adj[x].begin());

            if (k > 1)

                cout << " ";

            cout << p;

            adj[p].erase(x);

            if (adj[p].size() == 1)

                leafs.push (p);

        }

        cout << endl;

    }

    return 0;

}

 

你可能感兴趣的:(code)