树形dp小结

Posted wtz2333

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树形dp小结相关的知识,希望对你有一定的参考价值。

做了好久的树形DP(大雾) ,(noip)csp-s考了好多树形DP
树形DP基本分为这几种

1.最大独立集(没有上司的舞会)

经典树形DP
(dp[i][0/1]) 表示i这个点选与不选。
(dp[u][0] += dp[v][1];)
(dp[u][1] += max(dp[v][0],dp[v][1]);)

2.最小点覆盖(战略游戏)

状态与上面一样
(dp[u][0] += dp[v][1];)
(dp[u][1] += min(dp[v][0],dp[v][1]);)

3.最小支配集(SDOI保安站岗)

(dp[i][0/1/2]) 表示这个点被自己覆盖,被儿子覆盖,被父亲覆盖
(dp[u][0] += min(dp[v][0],dp[v][1],dp[v][2]);)
(dp[u][1] += min(dp[v][1],dp[v][0]);)
(注:如果u所有的儿子v的dp[v][1] < dp[v][0] 强制选一个最小的dp[v][0]);
(dp[u][2] += min(dp[v][0],dp[v][1]);)

   int dt=1e9+7,cnt=0;f[u][1]=pa[u];
    for(int p=last[u];p;p=pre[p])
    {
        int v=other[p];
        if(v==fa)continue;
        dfs(v,u);
    }
    for(int p=last[u];p;p=pre[p])
    {
        int v=other[p];
        if(v==fa)continue;
        f[u][1]+=min(min(f[v][2],f[v][1]),f[v][0]);
        f[u][2]+=min(f[v][1],f[v][0]);
        if(f[v][1]<f[v][0])cnt = 1;
        else dt=min(dt,f[v][1]-f[v][0]);
        f[u][0]+=min(f[v][1],f[v][0]);
    }
    if(cnt==0)
    f[u][0]+=dt;

4.Computer

求树上每个点到最远点的距离
(dp[i][0/1/2]) 分别表示子树内最长链,次长链,子树外最长链

inline void dfs1(int x,int fa)
{
    int fis = 0 ,sec = 0;
    for(int p = last[x];p;p = pre[p])
    {
        int v = other[p];
        if(v == fa)continue;
        dfs1(v,x);
        int tmp = dp[v][0] + len[p];
        if(tmp >= fis)
        sec = fis,fis = tmp;
        else if(tmp > sec)
        sec = tmp;
    }
    dp[x][0] = fis;dp[x][1] = sec;
}
inline void dfs2(int x,int fa)
{
    for(int p = last[x];p;p = pre[p])
    {
        int v = other[p];
        if(v == fa)continue;
        if(dp[v][0] == dp[x][0] - len[p])
        dp[v][2] = len[p] + max(dp[x][1],dp[x][2]);
        else 
        dp[v][2] = len[p] + max(dp[x][2],dp[x][0]);
        dfs2(v,x);
    }
}

5.树上背包(选课,有线电视网)

(dp[i][j]) 表示子树i中选了j门课
$ dp[u][j] = max(dp[u][j],dp[v][j-k] + dp[u][k]) $

   for(int p=last[u];p;p=pre[p])
    {
        int v=other[p];
        for(int i=m+1;i>=1;i--)
        {
            for(int j=i;j>=1;j--)
            if(f[u][j]>=0&&f[v][i-j]>=0)
            f[u][i]=max(f[u][i],f[u][j]+f[v][i-j]);
        }
    }

复杂度(O(nm^{2}))
用dfn序优化之后就是(O(nm))
树上背包基本都是这个套路
特别的像HAOI树上染色一题

     for(int i = min(siz[u],k) ; i >= 0 ;i--)
        {
            for(int j = 0; j <= min(siz[v],i);j++)
            {
                if(f[u][i-j] == -1)continue;
                ll val = (ll)(k-j)*j*len[p] + (ll)(siz[v]-j)*(n-k-siz[v]+j)*len[p];
                f[u][i] = max(f[u][i],f[v][j] + f[u][i-j] + val);
            }
        }

取min的两个位置要特别注意,如果不取min的话复杂度就是错的,这其中的道理不好分析,但这样做完之后,复杂度就是(O(n^{2}))

总结

树形DP多数分为(dp[i][0/1]),和背包几种类型,主要考虑子树中对当前点的贡献,或者子树外对当前点的贡献,来写出方程。

以上是关于树形dp小结的主要内容,如果未能解决你的问题,请参考以下文章

本周小结(未完工)

2016集训测试赛(二十五)小结

使用elementui树形控件写项目小结

动态规划_计数类dp_数位统计dp_状态压缩dp_树形dp_记忆化搜索

Starship Troopers(HDU 1011 树形DP)

HDU1520 Anniversary party(树形dp入门题)