hdu5834

题目让求得是从任意一点出发可以不回来得到的最大的价值

这应该不算特别水的树形dp了,它不止要从上往下dfs,后来海要重新dfs,根据父亲节点更新儿子节点,算是正常的树形dp中比较简单的吧。

思路:

  先从上往下dp,求出从该节点往下来在回到该节点的最大价值,不用回到该节点的最大价值以及此时停在哪一颗子树上,不用回到该节点且不停在前面的子树上的最大价值(只是不用回到该节点,不是一定不能回到该节点)

然后重新dfs,计算出儿子节点往上能回来的最大价值以及不用回来的最大价值,显然结果就是max(往下再回来的最大价值+往上不用回来的最大价值,往下不用回来的最大价值+往上再回来的最大价值)。

代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int val[100010];
int ans[100010];
int val1[100010];//回到自身
int val2[100010];//没有回到自身
int val3[100010];//次优
int id[100010];//最后从哪个枝上面走了之后没有回到自身
vector<pair<int,int> >v[100010];
void dfs1(int s,int fa)
{
    val1[s]=val2[s]=val3[s]=val[s];
    for(int i=0;i<v[s].size();i++)
    {
        int t=v[s][i].first;
        int c=v[s][i].second;
        if(t==fa)
            continue;
        dfs1(t,s);
        int temp=max(val1[t]-2*c,0);
        val2[s]+=temp;
        val3[s]+=temp;
        if(val1[s]+val2[t]-c>val2[s])
        {
            val3[s]=val2[s];
            val2[s]=val1[s]+val2[t]-c;
            id[s]=t;
        }
        else if(val1[s]+val2[t]-c>val3[s])
            val3[s]=val1[s]+val2[t]-c;
        val1[s]+=temp;
    }
}
void dfs2(int s,int fa,int temp3,int temp4)
{//temp3表示向上走还要回来能得到的优势,temp4对应的是不回来的
    ans[s]=max(val1[s]+temp4,val2[s]+temp3);
    val2[s]+=temp3;
    val3[s]+=temp3;
    if(val2[s]<=val1[s]+temp4)//更新向上走了之后对应的结果
    {
        val2[s]=val1[s]+temp4;//这地方不更新val3[s]是因为一定用不到val3[s]了
        id[s]=fa;
    }
    else if(val3[s]<=val1[s]+temp4)
        val3[s]=val1[s]+temp4;
    val1[s]+=temp3;
    for(int i=0;i<v[s].size();i++)
    {
        int t=v[s][i].first;
        int c=v[s][i].second;
        if(t==fa)
            continue;
        int temp1=max(0,val1[s]-2*c-max(0,val1[t]-2*c));
        int temp2;
        if(id[s]==t)
            temp2=max(0,val3[s]-c-max(0,val1[t]-2*c));
        else temp2=max(0,val2[s]-c-max(0,val1[t]-2*c));
        dfs2(t,s,temp1,temp2);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&val[i]);
            v[i].clear();
        }
        int a,b,c;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            v[a].push_back(make_pair(b,c));
            v[b].push_back(make_pair(a,c));
        }
        memset(id,-1,sizeof(id));
        dfs1(1,-1);
        dfs2(1,-1,0,0);
        printf("Case #%d:\n",cas);
        for(int i=1;i<=n;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}
时间: 2024-10-25 22:26:23

hdu5834的相关文章

树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree

1 // 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree 2 // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以走多次,问从每个点出发的最大获益 3 // 思路: 4 // dp[i]: 从i点出发回到i点的最大值 5 // d[i][0] 从i点出发不回来的最大值 6 // d[i][1] 从i点出发取最大值的下一个点 7 // d[i][2] 从i点出发取次大值 8 // dfs1处理出这四个 9

hdu5834 Magic boy Bi Luo with his excited tree 【树形dp】

题目链接 hdu5834 题解 思路很粗犷,实现很难受 设\(f[i][0|1]\)表示向子树走回来或不回来的最大收益 设\(g[i][0|1]\)表示向父亲走走回来或不回来的最大收益 再设\(h[i]\)为\(f[i][0]\)的次优收益 对于\(f[i][1]\),贪心选择所有\(f[v][1] - 2 * w \ge 0\)的子树即可 对于\(f[i][0]\),贪心选择所有没有被选的子树的\(f[v][0] - w \le 0\)的最大值 或者 被选子树\(f[v][1] - 2 * w

hdu5834 Magic boy Bi Luo with his excited tree(树形dp)

Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 723    Accepted Submission(s): 192 Problem Description Bi Luo is a magic boy, he also has a migic tree,

&lt;hdu5834 Magic boy Bi Luo with his excited tree&gt; (树形DP)

题意:一棵树有点权和边权 从每个点出发 走过一条边要花费边权同时可以获得点权 边走几次就算几次花费 点权最多算一次 问每个点能获得的最大价值 题解:好吧 这才叫树形DP入门题 dp[i][0]表示从i节点的儿子中走又回到i的最大值 dp[i][1]表示不回到i的最大值 dp[i][2]表示不回到i的次大值 同时需要记录不回到i最大值的方向id[x] 很显然 第一遍dfs可以预处理每个节点往下的值 然后关键的就是每个节点从父亲这个方向的值怎么处理 有个很显然的结论就是 不回来是肯定比回来更优的 所