问题:
算法训练 结点选择
时间限制:1.0s 内存限制:256.0MB
问题描述
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
输入格式
第一行包含一个整数 n 。
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
1 2 3 4 5
1 2
1 3
2 4
2 5
样例输出
12
样例说明
选择3、4、5号点,权值和为 3+4+5 = 12 。
数据规模与约定
对于20%的数据, n <= 20。
对于50%的数据, n <= 1000。
对于100%的数据, n <= 100000。
权值均为不超过1000的正整数。
分析:和MIT的课后题 Party 一样
算法:根节点a,它的子节点为bi。。每个节点保留着两个值,I和N作为选与不选的情况下的最大值
则如果a点选择,则I=sum(N(bi)))+value-of-a;
如果a点不选,则M=sum(max ( I(bi) , M(bi) ) );
由此递归
数据结构选择邻接表存储,也可以选择二叉树存储
代码:
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
#define maxn 100002
struct Po{
vector<int> xl;
int I,N;
}s[maxn];
//vector<int> s[maxn];
int vis[maxn];
int a[maxn];
void fun(int t){
vis[t]=1;
int m1=a[t],m2=0;
for(int i=0;i<s[t].xl.size();i++){
if(!vis[s[t].xl[i]]){
fun(s[t].xl[i]);
m1+=s[s[t].xl[i]].N;
m2 += max(s[s[t].xl[i]].N,s[s[t].xl[i]].I);
}
}
s[t].I=m1;
s[t].N=m2;
}
int main(){
memset(vis,0,sizeof(vis));
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}int a1,a2;
for(int i=1;i<n;i++){
cin>>a1>>a2;
s[a1].xl.push_back(a2);
s[a2].xl.push_back(a1);
}
int m1=a[1],m2=0;
vis[1]=1;
for(int i=0;i<s[1].xl.size();i++){
fun(s[1].xl[i]);
m1+=s[s[1].xl[i]].N;
m2 += max(s[s[1].xl[i]].N,s[s[1].xl[i]].I);
}
cout<<max(m1,m2)<<endl;
return 0;}