树形dp专栏

Posted baseai

tags:

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

前言

自己树形dp太菜了,要重点搞

219D Choosing Capital for Treeland

终于自己做了一道不算那么毒瘤的换根dp

(f[u]) 表示以 (u) 为根,子树内总共需要交换的边数, (up[u]) 表示以 (u) 为根,子树外总共需要交换的边数。

Dfs1 求出 (f[u]) ,就有:

[f[u]=sum_{v∈son[u]} f[v] + (edge[u->v] == 1)]

edge[u->v] 表示 u->v 这条边的方向是不是 u->v

Dfs2 求出 (up[v])注意,是从u点求u的儿子点v),容斥一下,就有:

[up[v]=f[u]-f[v]+up[u]+(+1 / -1)]

(+1 / -1) 是看 edge[u->v]是否等于 1,是的话就有多一条边交换方向,不是的话就要-1,因为多算了一条边

Code

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
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<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
const int N = 2e5+7;
int n,cnt;
int head[N],f[N],up[N];
struct Edge {
    int next,to,flag;
}edge[N<<1];
inline void add(int u,int v,int flag) {
    edge[++cnt] = (Edge)<%head[u],v,flag%>;
    head[u] = cnt;
}
void Dfs1(int u,int fa) {
    for(int i=head[u];i;i=edge[i].next) {
        int v = edge[i].to;
        if(v != fa) {
            Dfs1(v,u);
            f[u] += f[v] + (edge[i].flag==0); //·′±? 
        }
    }
}
void Dfs2(int u,int fa) {
    for(int i=head[u];i;i=edge[i].next) {
        int v = edge[i].to;
        if(v != fa) {
            up[v] = f[u] - f[v] + up[u];
            if(edge[i].flag == 1) up[v]++;
            else up[v]--;
            Dfs2(v,u);
        }
    }
}
int main()
{
    n = read();
    for(int i=1,u,v;i<=n-1;++i) {
        u = read(), v = read();
        add(u,v,1), add(v,u,0);
    }
    Dfs1(1,0);
    Dfs2(1,0);
    int ans = INF;
    for(int i=1;i<=n;++i)
        ans = min(ans,f[i]+up[i]);
    printf("%d
",ans);
    for(int i=1;i<=n;++i)
        if(f[i]+up[i] == ans) printf("%d ",i);
    return 0;
}
/*
4
1 4
2 4
3 4

2
1 2 3 
*/

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

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

Starship Troopers(HDU 1011 树形DP)

HDU1520 Anniversary party(树形dp入门题)

[填坑][支线任务]树形DP 树形背包

hdu1561 树形dp+背包

BZOJ_1060_时态同步_树形DP