zoukankan      html  css  js  c++  java
  • P3177 [HAOI2015]树上染色

    传送门

    显然考虑 $n^2$ 的树形 $dp$

    设 $f[x][i]$ 表示 $x$ 的子树内选了 $i$ 个节点染黑,子树内所有边对整颗树的最大贡献

    考虑子树的合并,显然对于 $(u,v),v in son[u]$ ,设边权为 $w$ ,这条边的贡献可以通过 $v$ 子树内的黑节点数算出

    因为确定了子树内的黑节点数就可以算出子树外的黑节点数,子树白节点也可以用子树节点数减去子树黑节点数得到

    那么贡献就容易确定

    那么对于 $f[u][i]$ ,枚举儿子 $v$ 并枚举 $v$ 内的黑节点数 $j$ ,有转移:

    $f[u][i]=max(f[u][i],f[u][i-j]+f[v][j]+wj(K-j)+w(sz[v]-j)(n-sz[v]-K+j))$

    注意代码实现的时候 $i$ 要从大到小枚举,并且 $j$ 要先把 $j=0$ 的情况转移好,才能保证 $f[u][i-j]$ 此时不包括 $v$ 的贡献

    这个代码实现的时候复杂度是 $n^2$ ,因为枚举当前的 $sz[x]$ 和下一个儿子 $v$ 的 $sz[v]$ 时枚举次数可以看成点对数(在 $v$ 内的点和在之前儿子子树的点)

    显然每个点对只会在 $lca$ 处枚举到

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=2007;
    int n,m,sz[N];
    int fir[N],from[N<<1],to[N<<1],val[N<<1],cntt;
    inline void add(int a,int b,int c) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; val[cntt]=c; }
    ll f[N][N];
    void dfs(int x,int fa)
    {
        sz[x]=1; memset(f[x],-1,sizeof(f[x]));
        f[x][0]=f[x][1]=0;
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i],&w=val[i]; if(v==fa) continue;
            dfs(v,x); sz[x]+=sz[v];
            for(int j=min(sz[x],m);j>=0;j--)
                for(int k=0;k<=min(sz[v],j);k++)//
                    if(f[x][j-k]>=0&&n-sz[v]>=m-k)
                        f[x][j]=max(f[x][j], f[x][j-k] + f[v][k] + 
                        1ll*w* ( k*(m-k) + (sz[v]-k)*(n-sz[v]-m+k) ) );
        }
    }
    int main()
    {
        n=read(),m=read(); int a,b,c;
        for(int i=1;i<n;i++)
        {
            a=read(),b=read(),c=read();
            add(a,b,c),add(b,a,c);
        }
        dfs(1,0);
        printf("%lld
    ",f[1][m]);
        return 0;
    }
  • 相关阅读:
    xna 添加一个精灵1
    【leetcode】705. 设计哈希集合
    【leetcode】1603. 设计停车系统
    【leetcode】设计有序流
    【leetcode】旅行终点站
    【leetcode】检测大写字母
    【leetcode】重复至少 K 次且长度为 M 的模式
    【leetcode】二叉树的直径
    【leetcode】公交站间的距离
    【leetcode】分糖果
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11751670.html
Copyright © 2011-2022 走看看