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;
}

 

posted on 2012-09-02 21:36  pcoda  阅读(939)  评论(0编辑  收藏  举报