Decode the Tree poj2568(Prufer序列)
zoj 1965
题目要求,由题目给的prufer序列,得到无根树的广义表表示。
1.树的组成元素一定是1-n这个范围。 所以在序列中最大的数字就是树的结点个数。
2.树的每一个结点的度数 = 数字的出现次数 + 1 ; 未出现的结点,则度数是0+1 ,为 1
思路:
首先把1-n中,prufer序列中未出现的数字进入优先队列。给每一个结点记录度数,用 ans[n ] 作为后面连接的基础。
根据已有的prufer序列,从头开始匹配。
匹配方式: 从优先队列中出队一个数字,把这个数字作为当前prufer序列第一个数字的子节点。
然后, 把(prufer序列 第一个数字)这个结点的度数减一(这里表示的是已经完成一个结点的连接) 连接用vector, 因为一个vector[x]可以连接任意个子节点,可以理解成二维数组,第二维是任意大小的。
连接完成后, 输出用广义表组成的无根树的表示。
用dfs (int start ), 这里类似图结构。一个点的子叶子 已经不只一个了。
注意这里开始的点是 1-n中最大的数字,即 n ,无根树,人为选择n 为根。不分左右结点
#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
#include<string>
#include<sstream>
#include<algorithm>
#include<vector>
using namespace std;
int f[55],ans[55];
vector<int> vec[55];
bool cmp(const int &a,const int &b)
{
return a<b;
}
void dfs(int x)
{
printf("(");
printf("%d",x);
int l=vec[x].size(); //该节点的度数是l
sort(vec[x].begin(),vec[x].end(),cmp);//vector排序
for(int i=0;i<l;i++)
{
printf(" ");
dfs(vec[x][i]);
}
printf(")");
vec[x].clear();//清空vector以防影响下组数据
}
int main()
{
int i,n=0;
char c;
string line;
memset(ans,0,sizeof(ans));
while(getline(cin,line))//输入'EOF'停止
{
stringstream ss(line);//用sstream类库读取数据
for(n=0;ss>>f[n];n++)//保留结点的度数。
ans[f[n]]++;
n--;
priority_queue<int,vector<int>,greater<int> > leafs;
for(i=1;i<=n+1;i++)
if(!ans[i]) leafs.push(i); //最初始的叶子,进入队列。
for(i=0;i<=n;i++)
{
int k=leafs.top(); //取出叶子中最小的数字
leafs.pop();
vec[f[i]].push_back(k); //连接到prud序列中,f 表示一个序列。由下标索引
if(--ans[f[i]]==0) leafs.push(f[i]); //连接后,把该结点的度数-1, 连接的结点多了一个。
}
if(n!=-1) dfs(f[n]);
else printf("(1)");//输入为0
printf("\n");
memset(ans,0,sizeof(ans));
}
}