luogu P1122(树形dp)

传送门

题意:

给你一个有\(n\)个结点的树,每个结点有一个权值,现在你可以把任意一条边断掉,此时会形成两棵树,你需要舍去其中一棵树,并统计另外一棵树上所有结点的权值。现在你可以做若干次上述操作,问你可以获得的最大权值。

分析:

这是一个比较经典的树形\(dp\)的模型。

我们设\(dp[i]\)为以结点\(i\)为根的树的最大权值,那么对于它的儿子,我们有选和不选(不选代表把儿子的子树都割掉了)两种状态。因此我们不难发现,当前的状态可以由儿子的选和不选这两种状态转移过来(若选取该儿子,则我们只需要令权值增加\(dp[son[i]]\)即可,否则增加\(0\)),故有状态转移方程\(dp[i]+=\max(dp[son[i],0])\) 。而我们在进行\(dfs\)的过程正好是完成了自底向上更新的过程,因此我们只需要在\(dfs\)的过程中进行更新即可。

代码

#include <bits/stdc++.h>
#define maxn 16005
using namespace std;
struct Node{
    int to,next;
}q[maxn<<1];
int head[maxn],cnt=0,dp[maxn],val[maxn],tmp[maxn],n;
int vis[maxn],maxx=0;
void add_edge(int from,int to){
    q[cnt].to=to;
    q[cnt].next=head[from];
    head[from]=cnt++;
}
void init(){
    memset(head,-1,sizeof(head));
    cnt=0;
}
void dfs(int x){
    dp[x]=val[x];
    vis[x]=1;
    for(int i=head[x];i!=-1;i=q[i].next){
        int to=q[i].to;
        if(vis[to]) continue;
        dfs(to);
        dp[x]+=max(dp[to],0);
    }
    maxx=max(maxx,dp[x]);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&val[i]);
    }
    init();
    for(int i=1;i<n;i++){
        int from,to;
        scanf("%d%d",&from,&to);
        add_edge(from,to);
        add_edge(to,from);
    }
    dfs(1);
    printf("%d\n",maxx);
    return 0;
}

转载于:https://www.cnblogs.com/Chen-Jr/p/11180880.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值