您的位置:首页 > 编程语言 > C语言/C++

第六届蓝桥杯C/C++第10题生命之树解题报告

2015-04-17 15:20 246 查看
题目:在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

思路:

这是一很简单的树规,只要把握好根节点与下属子树的关系就可以出思路,然后用个DFS就暴力破掉,算法时间复杂度O(n),空间算不了管他咧,反正不会爆就是了;

首先我们来转换一下题目,他说了那么多,我们可以从中提炼出我们是在找这个树的一个权值最大的一个子树,也就是集合S且集合S不能为空;

好,现在目标已经确定,我们就来看看怎么找,首先,每一个树的子树都只有两种情况,要么是包含自身的根结点,要么是不包含根结点,那么父结点和下属子树有什么关系呢?再看看题目我们已经把它转化成找这个树的一个权值最大的子树,那么父结点和下属子树的关系不就是:“要么最大的是包含父结点的一颗下属最大子树,要么就是    不包含父结点的一颗下属最大子树;”

动态转移方程MaxTree=Max(connet_max,unconnet_max);

PS:树规转移方程不像普通动规一样可以直接套,他只是给你一种编程思路,比如MAX()怎么求这个MAX 树规方程不能完全写出来 这个要自己去实现它

基本思路讲完 直接上代码:

#include <iostream>
using namespace std;
const int Min= 0x0fffffff * -1;  //求INT的最小值
inline int GetMax(int a,int b){ return a > b? a : b; }

class Graph
{
public:
class Vex;
class Edg
{
public:
Edg *next;
Vex *to_node;
Edg():next(NULL),to_node(NULL){}
};
class Vex
{
public:
Edg *e_first;
bool block;//判断是否被遍历过
int m_weight;//当前的结点权值
int c_max;//当前含根子树的最大权值
int unc_max;//当前不含根子树的最大权值
Vex():e_first(NULL),m_weight(0),c_max(0),unc_max(Min),block(false){}
//构造邻接表
void Add(Vex *right)
{
Edg *e=new Edg();
e->next=e_first;
e->to_node=right;
e_first=e;
}
void Connet(Vex *right)
{
Add(right);
right->Add(this);
}

};
Vex *v;
Graph(int n)
{
v=new Vex[n+1];
}
void DFS(Vex *v)
{
v->block=true;
for(Edg *e=v->e_first;e;e=e->next)
{
if(e->to_node->block)
continue;
DFS(e->to_node);
//状态转移方程
v->c_max += GetMax(e->to_node->c_max,0);//如果下属含根结点最大子树是正数 累加;
v->unc_max=GetMax(GetMax(e->to_node->c_max,e->to_node->unc_max),v->unc_max);/*下属最大子树有两种情况 含根或不含根  哪个大就把哪个													赋值给父结点*/
}
v->block=false;
}
};

int main(int argc, char** argv) {
int n,w,u,to;
cin>>n;
Graph G(n);
for(int i=1;i<=n;++i)
{
cin>>w;
G.v[i].m_weight=w;
G.v[i].c_max=w;
}
for(int i=1;i<n;++i)
{
cin>>u>>to;
G.v[u].Connet(G.v+to);
}
G.DFS(G.v+1);
cout<<GetMax(G.v[1].c_max,G.v[1].unc_max);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: