码迷,mamicode.com
首页 > 其他好文 > 详细

某不知名的树形Dp

时间:2020-04-11 23:30:22      阅读:75      评论:0      收藏:0      [点我收藏+]

标签:int   name   计算   接下来   增加   统计   怎么   用两个   head   

题意

给出一个\(N\)个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大

分析

看到树,还让求最大,这种可能不是贪心就是树形\(DP\),贪心的话树的形状没法判断,果断放弃,那么就只能是\(DP\)了。
既然它让求深度之和,那么我就直接定义以\(i\)为根时深度和为\(DP_i\),接下来就是怎么转移的问题了。如果我枚举每个点来考虑,那么还要计算它下边的子树和它上边的子树,显然是不好弄,时间复杂度可能在\(O(N^2)\)左右,虽然时间十秒但也不够用啊,由于\(n\)大到了1000000,所以这个题还是得用\(O(n)\)的效率,如果我以某种手段得到了\(DP_1\),那么接下来的转移就好说了,每次往下找一个儿子\(v\),深度减小了\(siz_v\),增加了\(n-siz_v\),这样就能用两个\(O(n)\)来完成这个题,最后在\(O(n)\)的统计一下答案就好。

#include<cstdio>
using namespace std;
const int N=1e6+10;
struct Edge{
    int to,nxt;
}e[N<<1];
int dep[N],Head[N],len;
void Ins(int a,int b){
    e[++len].to=b;e[len].nxt=Head[a];Head[a]=len;
}
int dp[N],siz[N];
void dfs(int u,int fa){
    siz[u]=1;dp[u]=dep[u];
    for(int i=Head[u];i;i=e[i].nxt){
        int v=e[i].nxt;
        if(v==fa)continue;
        dep[v]=dep[u]+1;
        dfs(v,u);
        siz[u]+=siz[v];
        dp[u]+=dp[v];
    }
}    
int n;
void calc(int u,int fa){
    for(int i=Head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa)continue;
        dp[v]=dp[u]-siz[v]+n-siz[v];
        calc(v,u);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        Ins(a,b);Ins(b,a);
    }
    dfs(1,0);
    calc(1,0);
    int ans=0;
    for(int i=1;i<=n;i++)
        if(dp[ans]<dp[i])ans=i;
    printf("%d\n",ans);
}

总结

转移方程题目问什么设什么先,求不出来再考虑换或者辅助一下\(DP\).

某不知名的树形Dp

标签:int   name   计算   接下来   增加   统计   怎么   用两个   head   

原文地址:https://www.cnblogs.com/anyixing-fly/p/12682898.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!