zoukankan      html  css  js  c++  java
  • 《算法竞赛进阶指南》0x54树形DP POJ3585积蓄程度

    题目链接:http://poj.org/problem?id=3585

    给定一棵树,边上面代表的是流量,可以选定一个点作为源点,一个点作为汇点,汇点的出量无限,源点的入量无限,问选择哪一个点能使得树中这个点为源点的流量最大。

    采用的算法是二次扫描与换根法,第一次扫描的时候选择一个root自底向上算出d的值,也就是从这个点出发向下的最大流量,一次扫描后root结点的流量是确定的,复制到f[root]中,接下来对自顶向下更新子树的f数组的值。更新的时候用上已经是真实f的父节点的f数组值以及当前点的d数组的值。注意在父节点和子节点是叶子节点的时候要单独计算f函数的值,因为实际上叶子结点计算的d数组值是0,但是实际上应该是inf,所以在d数组是非真实的时候要单独计算。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn = 200010;
    const int inf=0x3f3f3f3f;
    int n;
    int head[maxn],nxt[maxn<<1],len[maxn<<1],ver[maxn<<1];
    int f[maxn],d[maxn];
    int deg[maxn];
    int cnt=0;
    void addedge(int a,int b,int c){
        ver[++cnt]=b;
        len[cnt]=c;
        nxt[cnt]=head[a];
        head[a]=cnt;
    }
    void dfs_d(int u,int fa){
        d[u]=0;
        for(int i=head[u];i;i=nxt[i]){
            int v=ver[i];
            int w=len[i];
            if(v==fa)continue;
            dfs_d(v,u);
            if(deg[v]==1)d[u]+=w;
            else d[u]+=min(d[v],w);
        }
    }
    void dfs_f(int u,int fa){
    //u及以上的部分f数组已经计算完毕, 
    //通过父节点更新子节点的信息 
        for(int i=head[u];i;i=nxt[i]){
            int v=ver[i];
            int w=len[i];
            if(v==fa)continue;
            if(deg[u]==1)f[v]=d[v]+w;//父节点是叶子结点 
            else if(deg[v]==1)f[v]=min(f[u]-w,w);
            else f[v]=d[v]+min(f[u]-min(d[v],w),w);
                dfs_f(v,u);//计算以v为根节点的子树的所有f 
        }
    }
    int main(){
        int T;
        scanf("%d",&T);
        while(T--){
            cnt=0;
            scanf("%d",&n);
            memset(head,0,sizeof(head));
            memset(deg,0,sizeof deg);
            for(int i=0;i<n-1;i++){
                
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                addedge(a,b,c);
                addedge(b,a,c);
                deg[a]++,deg[b]++;
            }
            memset(d,0,sizeof(d));
            dfs_d(1,-1);//算出d数组 
            f[1]=d[1];
            dfs_f(1,-1);
            int res=0;
            for(int i=1;i<=n;i++)res=max(res,f[i]);
            
            printf("%d
    ",res);
        }
        return 0;
    } 
  • 相关阅读:
    HTTP状态码
    TCP慢启动、拥塞避免、快速重传、快速恢复(转)
    优化js设计,防止浏览器假死(转)
    Firebug详解(转)
    WUST Online Judge
    WUST Online Judge
    WUST Online Judge
    WUST Online Judge
    WUST Online Judge
    WUST Online Judge
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13412073.html
Copyright © 2011-2022 走看看