• 换根DP


    核心思想

    • dfs1.假设一个点为根,并以此求出问题的答案
    • dfs2.找到换根后答案的变化规律再做一次dp

    E.g1:

    来源:【POI2008-BZOJ1131】Sta
    题意:给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大
    链接:https://www.luogu.com.cn/problem/P3478

    • 题解:
      第一次DFS以1为根求出树的深度之和
      注意到:根由父节点x向子节点y变,以y为根的子树深度-1,其余节点+1,以此有:f[v]=f[x]+siz[1]-2*siz[v];
    • 代码
    #include <iostream>
    #include <cstdio>
    #define maxn 1000005
    using namespace std;
    int head[maxn],cnt,dep[maxn],siz[maxn],n;
    long long f[maxn];
    struct fdfdfd{int next,to;}e[maxn<<1];
    void addedge(int x,int y){e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;}
    void dfs(int x,int pre,int d)
    {
    	dep[x]=d; siz[x]=1;
    	for(int i=head[x];i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if(v==pre) continue;
    		dfs(v,x,d+1); dep[x]+=dep[v]; siz[x]+=siz[v];
    	}
    }
    void dp(int x,int pre)
    {
    	for(int i=head[x];i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if(v==pre) continue;
    		f[v]=f[x]+siz[1]-2*siz[v];
    		dp(v,x);
    	}
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1,u,v;i<n;++i) scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);
    	dfs(1,0,1); dp(1,0);
    	int k=1;
    	for(int i=2;i<=n;++i)
    		if(f[k]<f[i]) k=i;
    	printf("%d
    ",k);
    	return 0;
    }
    

    E.g2:

    来源:CF1092F Tree with Maximum Cost
    链接:https://www.luogu.com.cn/problem/CF1092F
    题解:https://www.luogu.com.cn/problem/solution/CF1092F

    • 代码
    #include <iostream>
    #include <cstdio>
    #define maxn 200005
    using namespace std;
    int head[maxn],cnt,dep[maxn],a[maxn];
    long long suma[maxn],f[maxn];
    struct fdfdfd{int next,to;}e[maxn<<1];
    void addedge(int x,int y){e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;}
    void dfs(int x,int pre,int d)
    {
    	dep[x]=d; suma[x]=a[x];
    	for(int i=head[x];i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if(v==pre) continue;
    		dfs(v,x,d+1); suma[x]+=suma[v];
    	}
    }
    void dp(int x,int pre)
    {
    	for(int i=head[x];i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if(v==pre) continue;
    		f[v]=f[x]+suma[1]-2*suma[v];
    		dp(v,x);
    	}
    }
    int main()
    {
    	int n; scanf("%d",&n);
    	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    	for(int i=1,u,v;i<n;++i) scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);
    	dfs(1,0,0);
    	for(int i=1;i<=n;++i) f[1]+=1ll*a[i]*dep[i];//初始化 以1为根时问题的答案
    	dp(1,0);
    	int k=1;
    	for(int i=2;i<=n;++i)
    		if(f[k]<f[i]) k=i;
    	printf("%lld
    ",f[k]);
    	return 0;
    }
    

    比较套路,树形DP的一个小分支

  • 相关阅读:
    Webbrowser中模拟连接点击(非鼠标模拟)
    用DDE控制Word
    禁止用键盘左右箭头,去切换PageControl页签
    Delphi实现全局鼠标钩子
    Delphi实现软件中登录用户的操作权限
    根据数据库结构生成TreeView
    根据字符串找到函数并执行
    用DLL实现插件的简单演示
    Delphi:窗体的扩展样式GWL_EXSTYLE用于SetWindowLong
    FastReport问题整理(http://129.sqdj.gov.cn/?p=77)
  • 原文地址:https://www.cnblogs.com/wuwendongxi/p/13775507.html
Copyright © 2020-2023  润新知