第六届蓝桥杯试题--生命之树 解题报告
2015-04-17 18:47
127 查看
原题:
在X森林里,上帝创建了生命之树。
他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值。
上帝要在这棵树内选出一个非空节点集S,使得对于S中的任意两个点a,b,都存在一个点列 {a, v1, v2, ..., vk, b} 使得这个点列中的每个点都是S里面的元素,且序列中相邻两个点间有一条边相连。
在这个前提下,上帝要使得S中的点所对应的整数的和尽量大。
这个最大的和就是上帝给生命之树的评分。
经过atm的努力,他已经知道了上帝给每棵树上每个节点上的整数。但是由于 atm 不擅长计算,他不知道怎样有效的求评分。他需要你为他写一个程序来计算一棵树的分数。
「输入格式」
第一行一个整数 n 表示这棵树有 n 个节点。
第二行 n 个整数,依次表示每个节点的评分。
接下来 n-1 行,每行 2 个整数 u, v,表示存在一条 u 到 v 的边。由于这是一棵树,所以是不存在环的。
「输出格式」
输出一行一个数,表示上帝给这棵树的分数。
「样例输入」
5
1 -2 -3 4 5
4 2
3 1
1 2
2 5
「样例输出」
8
「数据范围」
对于 30% 的数据,n <= 10
对于 100% 的数据,0 < n <= 10^5, 每个节点的评分的绝对值不超过 10^6 。
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms
解题思路 :
这是一道纯粹的树型动态规划题, 图的结构采用邻接表实现, 整个问题最后化简为"从一棵树中选取一棵结点权值和最大的子树(后面称其为最优子树)". 最优子树的存在形态只有两种:
1. 包含原树的根结点 ( 直接最优子树 ).
这种情况下, 原树的直接最优子树必然等于根结点加上它的下属子树中总权非负的直接最优子树.
2. 不包含原树的根结点 ( 间接最优子树 ).
这种情况下, 原树的间接最优子树必然是它的下属子树中的某一个具有最大权值的直接最优子树或间接最优子树( 谁大取谁 ).
如此一来, 状态转移方程就清晰了, 下面直接代码表示:
总结 :上述代码是赛后重新写的, 比赛时为了赶时间, 并没有写得那么多类, 但总体思路是一样的.
在X森林里,上帝创建了生命之树。
他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值。
上帝要在这棵树内选出一个非空节点集S,使得对于S中的任意两个点a,b,都存在一个点列 {a, v1, v2, ..., vk, b} 使得这个点列中的每个点都是S里面的元素,且序列中相邻两个点间有一条边相连。
在这个前提下,上帝要使得S中的点所对应的整数的和尽量大。
这个最大的和就是上帝给生命之树的评分。
经过atm的努力,他已经知道了上帝给每棵树上每个节点上的整数。但是由于 atm 不擅长计算,他不知道怎样有效的求评分。他需要你为他写一个程序来计算一棵树的分数。
「输入格式」
第一行一个整数 n 表示这棵树有 n 个节点。
第二行 n 个整数,依次表示每个节点的评分。
接下来 n-1 行,每行 2 个整数 u, v,表示存在一条 u 到 v 的边。由于这是一棵树,所以是不存在环的。
「输出格式」
输出一行一个数,表示上帝给这棵树的分数。
「样例输入」
5
1 -2 -3 4 5
4 2
3 1
1 2
2 5
「样例输出」
8
「数据范围」
对于 30% 的数据,n <= 10
对于 100% 的数据,0 < n <= 10^5, 每个节点的评分的绝对值不超过 10^6 。
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms
解题思路 :
这是一道纯粹的树型动态规划题, 图的结构采用邻接表实现, 整个问题最后化简为"从一棵树中选取一棵结点权值和最大的子树(后面称其为最优子树)". 最优子树的存在形态只有两种:
1. 包含原树的根结点 ( 直接最优子树 ).
这种情况下, 原树的直接最优子树必然等于根结点加上它的下属子树中总权非负的直接最优子树.
2. 不包含原树的根结点 ( 间接最优子树 ).
这种情况下, 原树的间接最优子树必然是它的下属子树中的某一个具有最大权值的直接最优子树或间接最优子树( 谁大取谁 ).
如此一来, 状态转移方程就清晰了, 下面直接代码表示:
#include <iostream> using namespace std; inline int GetMax( int a, int b){ return a>b?a:b;} inline int GetMax( int a, int b, int c){ return GetMax(GetMax(a,b),c);} const int N_Infinite = 0x7fffffff * -1; // ...负无穷值 class Vertex; class Edge{ // ...边 public: Edge *m_next; // ...出度顶点的下一条边 Vertex *m_to; // ...本边的指向 Edge():m_next(NULL),m_to(NULL){} }; class Vertex{ // ...顶点 public: Edge *m_edge; int m_val,m_maxSon,m_maxAll; // ...结点权值, 最大子树和(不含根顶点), 最大子树和(含自身根顶点) bool m_block; // ...阻塞标志 : 为true时表示正在阻塞, 不可遍历 Vertex():m_edge(NULL),m_val(0),m_block(false),m_maxSon(N_Infinite),m_maxAll(0){} void Add( Vertex *to,Edge* E){ // ...增加一条连接到顶点to的边 E->m_next = m_edge; E->m_to = to; m_edge = E; } }; class Graph{ // ...图 public: Edge *ESet; // ...边集 Vertex *VSet; // ...顶点集 int ESize; // ...边的数量 Graph( int N ){ ESet = new Edge[2*N]; VSet = new Vertex[N+1]; ESize = 0; } ~Graph(){ delete ESet;delete VSet;} void Add( int v1, int v2 ){ // ...在图中的v1与v2顶点间添加一条边 VSet[v1].Add(VSet+v2,ESet+ESize++); VSet[v2].Add(VSet+v1,ESet+ESize++); } static void DFS( Vertex *V ){ // ...遍历搜寻以顶点V为根的树的最大子树信息 V->m_block = true; // ...开始阻塞自身 V->m_maxAll = V->m_val; for( Edge *e = V->m_edge; e!=NULL;e=e->m_next){ // ...遍历所有下属子树 if( e->m_to->m_block == false ){ DFS( e->m_to ); V->m_maxSon = GetMax( e->m_to->m_maxAll, e->m_to->m_maxSon, V->m_maxSon); V->m_maxAll += GetMax( e->m_to->m_maxAll,0); } } V->m_block = false; // ...解除阻塞 } int GetVal(){ // ...获取图中的最大子树和 DFS( VSet+1 ); return GetMax( VSet[1].m_maxAll, VSet[1].m_maxSon ); } }; int main(int argc, char** argv) { int N,v1,v2; cin >> N; Graph G(N); for( int i = 1; i <= N; ++i ) cin >> G.VSet[i].m_val; for( int i = 1; i < N; ++i){ cin >> v1 >> v2; G.Add(v1,v2); } cout << G.GetVal(); return 0; }
总结 :上述代码是赛后重新写的, 比赛时为了赶时间, 并没有写得那么多类, 但总体思路是一样的.
相关文章推荐
- 第六届蓝桥杯校园选拔赛试题---派遣敢死队 解题报告
- 第六届蓝桥杯省赛试题--垒骰子 以矩阵的方法实现 解题报告
- 第六届蓝桥杯省赛试题--垒骰子 解题报告
- 第六届蓝桥杯C/C++第10题生命之树解题报告
- 第六届蓝桥杯大赛个人赛省赛(软件类)C++A组 解题报告
- 蓝桥杯 历届试题 危险系数 解题报告(并查集)
- 第六届蓝桥杯2015本科B组c/++部分解题报告
- 2015年第六届蓝桥杯省赛(C/C++ B组)解题报告
- 2015年第六届蓝桥杯省赛(C/C++ B组)解题报告
- 蓝桥杯 历届试题 连号区间数 解题报告
- 第六届蓝桥杯【省赛试题10】生命之树 ( 树形DP )
- 蓝桥杯 历届试题 买不到的数目 解题报告(完全背包,数论)
- 蓝桥杯 历届试题 九宫重排 解题报告(BFS,双向BFS优化)
- 第六届 蓝桥杯 第七题 手链样式 枚举 暴力 解题报告
- 2014 第六届蓝桥杯校内赛解题报告 答案
- 蓝桥杯第六届 第10题 生命之树
- 第六届蓝桥杯java试题-立方变自身
- 第五届蓝桥杯C/C++本科A组初赛波动数列解题报告
- 第六届蓝桥杯Java B组省赛试题答案
- 第五届蓝桥杯软件大赛C/C++本科B组决赛解题报告