牛客 树学 树形dp

思路:

如果是求根为1的点,整棵树的深度和,我们可以用一次dfs来统计每个节点的深度。

现在考虑换根:我们发现现在的根2的子树及2本身的深度都减1,其余点的深度都加1。

那么我们不仅需要统计每个点的深度,而且要统计每个节点子节点的数量cnti,再需要一次dfs。

然后最后一次dfs是dp的过程,考虑对于换根点v,其原来父节点为u,那么dpv=f[u]-cnt[i]+(n-cnt[i])。

最后求所有的dpi的最小值。

牛客 树学 树形dp_第1张图片

#include
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define INF 0x3f3f3f3f3f
using namespace std;
int dx[10] = { -1,1,0,0 };
int dy[10] = { 0,0,-1,1 };
const int maxn = 1000000 + 10;
int head[maxn<<1];
struct node
{
    int next,to;
}a[maxn<<1];
int cnt1;
void add(int u,int v)
{
    cnt1++;
    a[cnt1].to=v;
    a[cnt1].next=head[u];
    head[u]=cnt1;
}
int n;
int dep[maxn];
int cnt[maxn];
LL dp[maxn];
void dfs1(int u,int fa)
{
    for(int i=head[u];i;i=a[i].next)
    {
        int v=a[i].to;
        if(v==fa)continue;
        dep[v]=dep[u]+1;
        dfs1(v,u);
    }
}
void dfs2(int u,int fa)
{
    for(int i=head[u];i;i=a[i].next)
    {
        int v=a[i].to;
        if(v==fa)continue;
        dfs2(v,u);
        cnt[u]+=cnt[v];
    }
}
void dfs3(int u,int fa)
{
    for(int i=head[u];i;i=a[i].next)
    {
        int v=a[i].to;
        if(v==fa)continue;
        dp[v]=dp[u]-cnt[v]+n-cnt[v];
        dfs3(v,u);
    }
}
int main()
{
	scanf("%d",&n);
	rep(i,1,n-1)
	{
	    int u,v;
	    scanf("%d %d",&u,&v);
	    add(u,v);
	    add(v,u);
	}
	//求dep
	dfs1(1,0);
	rep(i,1,n)cnt[i]=1;
	dfs2(1,0);//求cnt
	for(int i=1;i<=n;i++)
    {
        dp[1]+=dep[i];
    }
    dfs3(1,0);
    LL minn=INF;
    for(int i=1;i<=n;i++)
    {
        minn=min(minn,dp[i]);
    }
    printf("%lld\n",minn);
}

 

你可能感兴趣的:(动态规划篇)