本文主要是介绍[hihocoder1490]Tree Restoration恢复树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
问题描述
题目2 : Tree Restoration
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
There is a tree of N nodes which are numbered from 1 to N. Unfortunately, its edges are missing so we don’t know how the nodes are connected. Instead we know:
Which nodes are leaves
The distance (number of edges) between any pair of leaves
The depth of every node (the root’s depth is 1)
For the nodes on the same level, their order from left to right
Can you restore the tree’s edges with these information? Note if node u is on the left of node v, u’s parent should not be on the right of v’s parent.
输入
The first line contains three integers N, M and K. N is the number of nodes. M is the depth of the tree. K is the number of leaves.
The second line contains M integers A1, A2, … AM. Ai represents the number of nodes of depth i.
Then M lines follow. The ith of the M lines contains Ai numbers which are the nodes of depth i from left to right.
The (M+3)-th line contains K numbers L1, L2, … LK, indicating the leaves.
Then a K × K matrix D follows. Dij represents the distance between Li and Lj.
1 ≤ N ≤ 100
输出
For every node from 1 to N output its parent. Output 0 for the root’s parent.
样例输入
8 3 5
1 3 4
1
2 3 4
5 6 7 8
3 5 6 7 8
0 3 3 3 3
3 0 2 4 4
3 2 0 4 4
3 4 4 0 2
3 4 4 2 0
样例输出
0 1 1 1 2 2 4 4
算法思路
基本的算法就是从下向上,每次处理一层;每层内部的处理是从左到右。
这样就有每次处理的层可以看做最底层,层内每个节点都可以看做叶子节点,而且每个节点都有其与其他叶子节点的距离。每层内部处理的时候交替应用以下规则:
1. 当前层未处理的最左侧节点的父亲节点一定是上一层未处理的且非叶子节点的最左侧节点。
2. 如果两个节点位于同一层且距离为2,那么它们的父亲节点相同。
数据结构
1. 节点
是否是叶子节点+名字+父亲节点的名字
struct Node {
public:bool leaf_flag;int name;int par_name;Node(bool lf=false,int n=-1,int pn = 0):leaf_flag(lf),name(n),par_name(pn) {}Node(const Node& n):leaf_flag(n.leaf_flag),name(n.name),par_name(n.par_name) {}~Node() {}
};
2. 节点集
节点的list。
Node nodes[102];
注意这里就有了对节点的两种索引方式:节点集列表的索引值,节点名称,分别用index/node和name指代,之后的变量命名规则也遵守这个规律。(通常情况下name=index+1,但是为了防止特殊情况,所以使用node2index[]用于两种方式之间的转换)
3. 距离矩阵
存储叶子节点之间的距离,索引值是节点的index。(因为是对称矩阵,实际存储的是个上三角矩阵)
之所以使用一个struct存储距离(而不是直接使用矩阵),就是因为矩阵是对称的,防止信息更新的不及时,或者重复更新。
struct Dist {
public:int dist[101][101];Dist() {}Dist(const Dist& d) {for (int i = 0;i < 101;++i) {for (int j = 0;j < 101;++j)dist[i][j] = d.dist[i][j];}}~Dist() {}int& get(int i,int j) {return dist[min(i,j)][max(i,j)];}
};
代码
1. 变量声明
Node nodes[102];int name2node[102]={0};int leaves_index[102] = {0};int N,M,K;Dist dist;int m_num[102] = {0},m_sum[102]={0};
2. 数据输入
cin >> N >> M >> K;for (int i = 0;i < M;++i) {cin >> m_num[i];m_sum[i+1] = m_sum[i]+m_num[i];}for (int i = 0;i < M;++i) {for (int j = 0;j < m_num[i];++j) {cin >> nodes[m_sum[i]+j].name;name2node[nodes[m_sum[i]+j].name] = m_sum[i]+j;}}int tmp_leaf_name=0,tmp_leaf_index=-1;for (int i = 0;i < K;++i) {cin >> tmp_leaf_name;tmp_leaf_index = name2node[tmp_leaf_name];nodes[tmp_leaf_index].leaf_flag = true;leaves_index[i] = tmp_leaf_index;}for (int i = 0;i < K;++i) {tmp_leaf_index = leaves_index[i];for (int j = 0;j < K;++j) {cin >> dist.get(tmp_leaf_index,leaves_index[j]);}}
3. 树结构重构
外层循环是层数循环,从低向上。内层循环是从左到右。
int cur_index=-1,par_index=-1;//从底向上处理每层for (int m = M-1;m > 0;--m) {//首先处理最左侧的节点cur_index = m_sum[m];par_index = m_sum[m-1];while (cur_index < m_sum[m+1]) {//寻找未处理的非叶子节点的最左侧的上层节点while (nodes[par_index].leaf_flag)++par_index;//应用算法规则1nodes[cur_index].par_name = nodes[par_index].name;//上层的节点就变为新的叶子节点,所以更新其与其他叶子节点的距离(之后只会使用还未处理的叶子节点之间的距离,所以不用在意会出现距离小于0的部分,因为之后不会用到)for (int i = 0;i < N;++i)dist.get(par_index,i) = dist.get(cur_index,i)-1;//从左到右处理++cur_index;++par_index;//应用算法规则2while (cur_index < m_sum[m+1] && dist.get(cur_index-1,cur_index) == 2) {nodes[cur_index].par_name = nodes[cur_index-1].par_name;++cur_index;}}}
4. 信息输出
for (int i = 1;i <= N;++i)cout << nodes[name2node[i]].par_name << ' ';cout << endl;
5. 全部代码
#include <iostream>
#include <fstream>using namespace std;struct Node {
public:bool leaf_flag;int name;int par_name;Node(bool lf=false,int n=-1,int pn = 0):leaf_flag(lf),name(n),par_name(pn) {}Node(const Node& n):leaf_flag(n.leaf_flag),name(n.name),par_name(n.par_name) {}~Node() {}
};struct Dist {
public:int dist[101][101];Dist() {}Dist(const Dist& d) {for (int i = 0;i < 101;++i) {for (int j = 0;j < 101;++j)dist[i][j] = d.dist[i][j];}}~Dist() {}int& get(int i,int j) {return dist[min(i,j)][max(i,j)];}
};int main()
{
// freopen("input.txt","r",stdin);Node nodes[102];int name2node[102]={0};int leaves_index[102] = {0};int N,M,K;Dist dist;int m_num[102] = {0},m_sum[102]={0};cin >> N >> M >> K;for (int i = 0;i < M;++i) {cin >> m_num[i];m_sum[i+1] = m_sum[i]+m_num[i];}for (int i = 0;i < M;++i) {for (int j = 0;j < m_num[i];++j) {cin >> nodes[m_sum[i]+j].name;name2node[nodes[m_sum[i]+j].name] = m_sum[i]+j;}}int tmp_leaf_name=0,tmp_leaf_index=-1;for (int i = 0;i < K;++i) {cin >> tmp_leaf_name;tmp_leaf_index = name2node[tmp_leaf_name];nodes[tmp_leaf_index].leaf_flag = true;leaves_index[i] = tmp_leaf_index;}for (int i = 0;i < K;++i) {tmp_leaf_index = leaves_index[i];for (int j = 0;j < K;++j) {cin >> dist.get(tmp_leaf_index,leaves_index[j]);}}int cur_index=-1,par_index=-1;for (int m = M-1;m > 0;--m) {cur_index = m_sum[m];par_index = m_sum[m-1];while (cur_index < m_sum[m+1]) {while (nodes[par_index].leaf_flag)++par_index;nodes[cur_index].par_name = nodes[par_index].name;for (int i = 0;i < N;++i)dist.get(par_index,i) = dist.get(cur_index,i)-1;++cur_index;++par_index;while (cur_index < m_sum[m+1] && dist.get(cur_index-1,cur_index) == 2) {nodes[cur_index].par_name = nodes[cur_index-1].par_name;++cur_index;}}}for (int i = 1;i <= N;++i)cout << nodes[name2node[i]].par_name << ' ';cout << endl;return 0;
}
这篇关于[hihocoder1490]Tree Restoration恢复树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!