HDU 6201 2017沈阳网络赛 树形DP或者SPFA最长路

Posted Lsxxxxxxxxxxxxx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6201 2017沈阳网络赛 树形DP或者SPFA最长路相关的知识,希望对你有一定的参考价值。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201

题意:给出一棵树,每个点有一个权值,代表商品的售价,树上每一条边上也有一个权值,代表从这条边经过所需要的花费。现在需要你在树上选择两个点,一个作为买入商品的点,一个作为卖出商品的点,当然需要考虑从买入点到卖出点经过边的花费。使得收益最大。允许买入点和卖出点重合,即收益最小值为0。

解法:我们设1为根节点,假设一开始一个人身上的钱为0。我们设dp[i][0]表示从根节点走到i及其子树并中任一点买入一本书后这个人身上钱的最大值(显然是负的)。dp[i][1]表示从根节点走到i及其子树并中任一点卖出一本书后这个人身上钱的最大值(可正可负)。那么我们对这棵树进行一次树形DP即可,dfs后对每个节点更新收益最大值,单点的计算方法为dp[i][0]+dp[i][1],树形DP的过程中即可维护这个最大值。

 

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 100010;
struct node{
    int v,w;
};
vector <node> G[maxn];
int val[maxn];
int dp[maxn][2];
int n, ans;
void dfs(int x, int pre){
    dp[x][0] = -val[x];
    dp[x][1] = val[x];
    for(int i=0; i<G[x].size(); i++){
        int v = G[x][i].v;
        int w = G[x][i].w;
        if(v == pre) continue;
        dfs(v, x);
        dp[x][0] = max(dp[x][0], dp[v][0]-w);
        dp[x][1] = max(dp[x][1], dp[v][1]-w);
    }
    ans = max(ans, dp[x][0]+dp[x][1]);
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        for(int i=0; i<=n; i++) G[i].clear();
        for(int i=1; i<=n; i++) scanf("%d", &val[i]);
        for(int i=1; i<n; i++){
            int u, v, w;
            scanf("%d %d %d", &u,&v,&w);
            G[u].push_back(node{v,w});
            G[v].push_back(node{u,w});
        }
        ans = 0;
        dfs(1,-1);
        printf("%d\n", ans);
    }
    return 0;
}

 

除了DP,还看到一个方法,就是建立源点和汇点。源点连所有的树上点, 边权为 a[i], 所有树上点在连接 汇点, 边权为-a[i]. 然后在根据树建图。 spfa跑个最长路即可。这个也可以用费用流,不过要注意是可行流。


以上是关于HDU 6201 2017沈阳网络赛 树形DP或者SPFA最长路的主要内容,如果未能解决你的问题,请参考以下文章

2019 沈阳网络赛 D Fish eating fruit ( 树形DP)

hdu-6201

HDU 6197 array array array 2017沈阳网络赛 LIS

HDU 6198 2017沈阳网络赛 线形递推

HDU 6205 2017沈阳网络赛 思维题

2016 年沈阳网络赛---QSC and Master(区间DP)