• P4438 [HNOI/AHOI2018]道路 树DP


    题意:

    戳这里

    分析:

    这个题意好阴间,转化一下大概就是,给定一颗二叉树,保证有 (n) 个叶子结点,(n-1) 个非叶子结点,每个点有两种边,求给定式子的最小值

    • 假做法

    我原本以为这个式子拆开之后可以分别计算贡献

    (c_u(a_u+x)(b_u+y)=a_ub_uc_u+c_ua_uy+a_ub_ux+c_uxy)

    开一个三元组分别统计 (x,y) 状态下的三个参数,但是这个贡献没有办法判断最优所以没法转移

    • 正解:

    我们发现刚才的式子没法转移是因为我们没有办法考虑加 一条公路/铁路带来的影响 ,那么我们的 DP 就需要避免这种情况,直接把一个点的所有贡献统计完,这也就要求我们必须知道它到根节点的路径上两种边的数目,而且转移还必须从下向上,因此我们得出另一种DP的方式 , (f[u][i][j]) 表示 (u) 到根节点的路径上有 (i) 条公路 (j) 条铁路,易得转移式如下:

    (f[u][i][j]=min(f[lc[u]][i][j]+f[rc[u][i]][j+1],f[lc[u]][i+1][j]+f[rc[u]][i][j]))

    最后的答案就是 (f[1][0][0])

    但是做到这里还没有完,如果完全按照这种方式 DP 的话空间复杂度是 (2n*40^2) 大约在 (3e7) 级别的 (long long) 会炸空间,所以我们要优化 DP ,,我们发现 DP 的时候只与 一条链有关,所以我们给链上的每一个点重标号,这样 DP 数组的第一维只要开到树上最长链的长度 (2*40) 就够了

    代码:

    #include<bits/stdc++.h>
    #define inl inline
    #define reg register
    
    using namespace std;
    
    namespace zzc
    {
        typedef long long ll;
        inl ll read()
        {
            ll x=0,f=1;char ch=getchar();
            while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
            while(isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
            return x*f;
        }
    
        const ll maxn = 1e5+5;
        ll n;
        ll lc[maxn],rc[maxn],a[maxn],b[maxn],c[maxn],dfn[maxn],dep[maxn];
        long long f[105][50][50];
        
        void dfs(ll u,ll k)
        {
            dfn[u]=k;
            if(lc[u])
            {
                dep[lc[u]]=dep[rc[u]]=dep[u]+1;
                dfs(lc[u],k+1);dfs(rc[u],k+2);
                for(ll i=0;i<=dep[u];i++)
                {
                    for(ll j=0;j<=dep[u];j++)
                    {
                        f[dfn[u]][i][j]=min(f[dfn[lc[u]]][i][j]+f[dfn[rc[u]]][i][j+1],f[dfn[lc[u]]][i+1][j]+f[dfn[rc[u]]][i][j]);
                    }
                }
            }
            else
            {
                for(ll i=0;i<=dep[u];i++)
                {
                    for(ll j=0;j<=dep[u];j++)
                    {
                        f[dfn[u]][i][j]=1ll*c[u]*(a[u]+i)*(b[u]+j);
                    }
                }
            }
        }
    
        void work()
        {
            memset(f,0x3f,sizeof(f));
            n=read();
            for(ll i=1;i<n;i++)
            {
                lc[i]=read();rc[i]=read();
                if(lc[i]<0) lc[i]=-lc[i]+n-1;
                if(rc[i]<0) rc[i]=-rc[i]+n-1;
            }
            for(ll i=n;i<=2*n-1;i++) a[i]=read(),b[i]=read(),c[i]=read();
            dfs(1,0);
            printf("%lld
    ",f[dfn[1]][0][0]);
        }
    
    }
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
  • 相关阅读:
    WPF 基础到企业应用系列1——开篇有益
    WPF 基础到企业应用系列2——WPF前世今生
    “云计算之旅”筹备完成,意见征询!
    31天重构学习笔记30. 尽快返回
    作为资深程序员,必定会掌握的十句谎话
    TaffyDB Writing queries
    TAFFY Working with data
    2012年全球最愚蠢的设计第一是微软,第二还是微软
    TaffyDB Introduction
    TaffyDB Beginner's Guide
  • 原文地址:https://www.cnblogs.com/youth518/p/14329392.html
Copyright © 2020-2023  润新知