节点选择(树形dp)

#include <bits/stdc++.h>
using namespace std;
int tree[100001],dp[100001],p[100001],n,x,y,mask[100001]={0},sons[100001]={0};
int rdp1[100001],rdp2[100001]={0},vis[100001]={0};
//树形dp,从下往上更新,具体见算法入门经典
//节点选择除了自上而下和枚举子子的另一种解法:
//用F[i]表示i这条根要,G[i]表示不要(也可以用f[i][1,0]来表示
//        f[root]+=g[ee[i].y];
//g[root]+=max(f[ee[i].y],g[ee[i].y]);
//要了就子不能要,没要,要不要都行
vector<int> points[100001];
queue<int> q;
void build(){
    queue<int> qq;
    qq.push(1);
    vis[1]=1;
    while(!qq.empty()){
        int pp=qq.front();
        qq.pop();
        for(vector<int>::iterator i=points[pp].begin();i!=points[pp].end();i++){
            if(vis[*i]==0){
                vis[*i]=1;
                qq.push(*i);
                p[*i]=pp;
                sons[pp]++;
            }
        }
    }
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>tree[i];
        rdp1[i]=tree[i];
        p[i]=-1;
    }
    for(int i=1;i<n;i++){
        cin>>x>>y;
        points[x].push_back(y);
        points[y].push_back(x);
        mask[x]++;
        mask[y]++;
    }
    build();
    for(int i=1;i<=n;i++)
        if(mask[i]==1)
            q.push(i);
    while(!q.empty()){
        int point=q.front();
        q.pop();
        dp[point]=max(rdp1[point],rdp2[point]);
        if(p[point]!=-1){
            rdp2[p[point]]+=dp[point];
            if(p[p[point]]!=-1) rdp1[p[p[point]]]+=dp[point];
            sons[p[point]]--;
            if(sons[p[point]]==0) q.push(p[point]);
        }
    }
    cout<<dp[1]<<endl;
    return 0;
}

 

posted @ 2020-06-06 21:15  西伯利亚挖土豆  阅读(269)  评论(0编辑  收藏  举报