zoukankan      html  css  js  c++  java
  • HDU 5834 Magic boy Bi Luo with his excited tree 树形dp

    题目链接:

    http://acm.split.hdu.edu.cn/showproblem.php?pid=5834

    Magic boy Bi Luo with his excited tree

    Time Limit: 8000/4000 MS (Java/Others)
    Memory Limit: 131072/131072 K (Java/Others)
    #### 问题描述 > Bi Luo is a magic boy, he also has a migic tree, the tree has N nodes , in each node , there is a treasure, it's value is V[i], and for each edge, there is a cost C[i], which means every time you pass the edge i , you need to pay C[i]. > > You may attention that every V[i] can be taken only once, but for some C[i] , you may cost severial times. > > Now, Bi Luo define ans[i] as the most value can Bi Luo gets if Bi Luo starts at node i. > > Bi Luo is also an excited boy, now he wants to know every ans[i], can you help him? #### 输入 > First line is a positive integer T(T≤104) , represents there are T test cases. > > Four each test: > > The first line contain an integer N(N≤105). > > The next line contains N integers V[i], which means the treasure’s value of node i(1≤V[i]≤104). > > For the next N−1 lines, each contains three integers u,v,c , which means node u and node v are connected by an edge, it's cost is c(1≤c≤104). > > You can assume that the sum of N will not exceed 106. #### 输出 > For the i-th test case , first output Case #i: in a single line , then output N lines , for the i-th line , output ans[i] in a single line. #### 样例 > **sample input** > 1 > 5 > 4 1 7 7 7 > 1 2 6 > 1 3 1 > 2 4 8 > 3 5 2 > > **sample output** > Case #1: > 15 > 10 > 14 > 9 > 15

    题意

    给你一颗树,每个点有价值,每个边有花费,价值只能取一次,花费每经过一次就要付一次,问从编号为x(x=1,...,n),能够获得的最大价值是多少。

    题解

    dp[u][0]:从u往下走能回来的最大价值
    dp[u][1]:从u往下走不回来的最大价值(也有可能根本不往下走哦),d[u]:从哪个位置出去不回来的
    dp[u][2]:从u往下走不回来的次大价值
    这些在第一次dfs的时候就能求出来。

    令up1表示从父亲出去不回来的最大价值,up2表示从父亲出去要回来的最大价值
    那么ans[i]=max(up1+dp[u][0],up2+dp[u][1])
    所以在dfs2中维护下up1,up2,就能往下推出所有的ans了。

    代码

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    using namespace std;
    #define X first
    #define Y second
    #define mkp make_pair
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    #define mid (l+(r-l)/2)
    #define sz() size()
    #define pb(v) push_back(v)
    #define all(o) (o).begin(),(o).end()
    #define clr(a,v) memset(a,v,sizeof(a))
    #define bug(a) cout<<#a<<" = "<<a<<endl
    #define rep(i,a,b) for(int i=a;i<(b);i++)
    #define scf scanf
    #define prf printf
    
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<pair<int,int> > VPII;
    
    const int INF=0x3f3f3f3f;
    const LL INFL=0x3f3f3f3f3f3f3f3fLL;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    
    //start----------------------------------------------------------------------
    
    const int maxn=1e5+10;
    
    int dp[maxn][3],id[maxn];
    int val[maxn],ans[maxn];
    
    VPII G[maxn];
    
    //dp[u][0]:从u往下走能回来的最大价值
    //dp[u][1]:从u往下走不回来的最大价值(也有可能根本不往下走哦),d[u]:从哪个位置出去不回来的
    //dp[u][2]:从u往下走不回来的次大价值
    void dfs(int u,int fa) {
        dp[u][0]=dp[u][1]=dp[u][2]=val[u];
        id[u]=-1;
        rep(i,0,G[u].sz()) {
            int v=G[u][i].X,w=G[u][i].Y;
            if(v==fa) continue;
            dfs(v,u);
            int tmp=dp[v][0]-2*w;
            if(tmp>0) dp[u][0]+=tmp;
        }
        rep(i,0,G[u].sz()) {
            int v=G[u][i].X,w=G[u][i].Y;
            if(v==fa) continue;
            int tmp=dp[u][0]-max(0,(dp[v][0]-2*w))+max(0,dp[v][1]-w);
            if(tmp>dp[u][1]) {
                dp[u][2]=dp[u][1];
                dp[u][1]=tmp;
                id[u]=v;
            } else if(tmp>dp[u][2]) {
                dp[u][2]=tmp;
            }
        }
    }
    
    //dfs2磨了很久,还是参考别人写出来的:http://www.cnblogs.com/hchlqlz-oj-mrj/p/5774196.html
    //当时一直想维护出全局的值,然后就晕了。。xrz
    //up1表示从父亲出去不回来的最大价值,up2表示从父亲出去要回来的最大价值
    void dfs2(int u,int fa,int up1,int up2) {
        ans[u]=max(up1+dp[u][0],up2+dp[u][1]);
        rep(i,0,G[u].sz()){
            int v=G[u][i].X,w=G[u][i].Y;
            if(v==fa) continue;
            int dwn2=up2+dp[u][0]-max(0,dp[v][0]-2*w);
            dwn2=max(0,dwn2-2*w);
            int dwn1=up1+dp[u][0]-max(0,dp[v][0]-2*w);
            dwn1=max(0,dwn1-w);
            if(id[u]!=v){
                int tmp=up2+dp[u][1]-max(0,dp[v][0]-2*w);
                tmp=max(0,tmp-w);
                dwn1=max(dwn1,tmp);
            }else{
                int tmp=up2+dp[u][2]-max(0,dp[v][0]-2*w);
                tmp=max(0,tmp-w);
                dwn1=max(dwn1,tmp);
            }
            dfs2(v,u,dwn1,dwn2);
        }
    }
    
    void init(){
        rep(i,0,maxn) G[i].clear();
    }
    
    int main() {
        int tc,kase=0;
        int n;
        scanf("%d",&tc);
        while(tc--) {
            scf("%d",&n);
            init();
            for(int i=1; i<=n; i++) scf("%d",&val[i]);
            rep(i,1,n) {
                int u,v,w;
                scf("%d%d%d",&u,&v,&w);
                G[u].pb(mkp(v,w));
                G[v].pb(mkp(u,w));
            }
    
            dfs(1,-1);
            dfs2(1,-1,0,0);
    
            prf("Case #%d:
    ",++kase);
            for(int i=1; i<=n; i++) {
                prf("%d
    ",ans[i]);
            }
        }
        return 0;
    }
    
    //end-----------------------------------------------------------------------
  • 相关阅读:
    Cassandra开发入门文档第三部分(非规范化关系结构、批处理)
    Cassandra开发入门文档第二部分(timeuuid类型、复合主键、静态字段详解)
    Cassandra开发入门文档第一部分
    Flume的Source、Sink总结,及常用使用场景
    Libgdx学习笔记:分享自己写的异步加载
    jquery easyui toolbar 分割线问题
    easyui datagrid设置fit: true后,页面显示不全的情况
    CentOS下安装JDK1.7
    CentOS 7搭建SVN服务器
    SWT中ole/activex实践--操作word的一个例子
  • 原文地址:https://www.cnblogs.com/fenice/p/5832819.html
Copyright © 2011-2022 走看看