题意
- 给定一颗n个结点的树,结点编号1~n,每个结点有权值,一个点选择以后,它的父亲就不可以被选,输出能选出的最大权值
思路
- 对于每个点,都有选和不选两种情况,当一个点选的时候,所有的儿子都不能选,当一个点不选的时候,每个儿子取选和不选的最大值即可,维护一个二维dp数组,状态转移方程如下
%24%24%24%24dp%5Bi%5D%5B1%5D%3Da%5Bi%5D%2B%5Csum_%7Bu%E6%98%AFi%E7%9A%84%E5%84%BF%E5%AD%90%7D%20dp%5Bu%5D%5B0%5D&preview=true)
- 注意到,由于涉及父子关系,所以考虑用有根树来维护,因为输入的时候每个除了根以外的结点都只出现一次,根不出现,所以用编号和不断减去结点编号,最终剩余的就是根
- 当然,本题也可以使用无根树来维护
代码
#include<bits/stdc++.h>
//有根树
using namespace std;
int a[10101],dp[10101][2];
vector<int> s[10101];
void dfs(int x){
dp[x][1]=a[x];
dp[x][0]=0;
for(auto i : s[x]){
dfs(i);
dp[x][0]+=max(dp[i][0],dp[i][1]);
dp[x][1]+=dp[i][0];
}
}
int main(){
int n;
cin >> n ;
int root = n*(n+1)/2;
for(int i=1;i<=n;i++){
cin >> a[i] ;
}
for(int i=1;i<n;i++){
int l,k;
cin >> l >> k ;
root -= l;
s[k].push_back(l);
}
dfs(root);
int ans = 0 ;
for(int i=1;i<=n;i++){
ans = max(dp[i][0],ans);
ans = max(dp[i][1],ans);
}
cout << ans << endl;
return 0;
}
//无根树
#include <bits/stdc++.h>
using namespace std;
const int maxn = 6000+10;
int f[maxn];
vector<int> v[maxn];
int dp[maxn][2];
void dfs(int x, int fa) {
int len = v[x].size();
dp[x][1] = f[x];
for (int i=0;i<len;i++) {
int next = v[x][i];
if (next == fa) continue;
dfs(next, x);
dp[x][1] += dp[next][0];
dp[x][0] += max(dp[next][0], dp[next][1]);
}
}
int main() {
int n;
int x, y;
cin>>n;
for (int i=1;i<=n;i++) {
cin>>f[i];
}
for (int i=1;i<=n;i++) {
cin>>x>>y;
v[x].push_back(y);
v[y].push_back(x);
}
dfs(1, 0);
cout<<(dp[1][0]>dp[1][1]? dp[1][0]:dp[1][1]);
return 0;
}