蓝桥杯 ALGO-4 结点选择 (树形动态规划)

问题描述

有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?

输入格式

第一行包含一个整数 n 。

接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。

接下来一共 n-1 行,每行描述树上的一条边。

输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
样例输出
12
样例说明
选择3、4、5号点,权值和为 3+4+5 = 12 。
 
一道最基础的 树形动态规划,今天重温一下,顺便温习一下邻接表的构建过程。
状态转移方程为:dp[s][0]+=dp[u][1];  dp[s][1]+=max(dp[u][0],dp[u][1]);(u为s的子节点,0表示包含自己的以s为根节点的子树最大值,1表示不包含自己的以s为根节点的子树最大值)
ac代码如下:
#include<iostream>
#include<cstring>
using namespace std;
struct edge{
    int e,next;
}e[300000];
int head[150000],val[150000];
int N,M=0;
void add(int s,int e1){
    e[++M].e=e1;
    e[M].next=head[s];
    head[s]=M;
}
long dp[150000][2];
bool v[150000];
void dfs(int s){
    dp[s][0]=val[s];
    dp[s][1]=0;
    for(int i=head[s];i!=-1;i=e[i].next){
        int u=e[i].e;
        if(v[u]==0){
            v[u]=1;
            dfs(u);
            dp[s][0]+=dp[u][1];
            dp[s][1]+=max(dp[u][0],dp[u][1]);
            v[u]=0;
        }
    }
}
int main(){
    cin>>N;
    int s,e;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=N;i++) cin>>val[i];
    for(int i=1;i<N;i++){
        cin>>s>>e;
        add(s,e);add(e,s);
    }
    int ans=0;
    memset(dp,0,sizeof(dp));
    memset(v,0,sizeof(v));
    v[1]=1;
    dfs(1);
    v[1]=0;
    ans=max(dp[1][0],dp[1][1]);
    cout<<ans<<endl;
    return 0;
}
 
原文地址:https://www.cnblogs.com/yifan2016/p/5268887.html