树形dp

一般解决方法 根->儿子,再由儿子->根,推出根的值

基本模型:

没有上司的舞会

任意两个一起跳舞的职员层次至少相差2(关系可以看成一棵树,相邻之间不能选择即该节点的父亲和儿子,根节点没有父亲)

一般解法:用f(x)表示x子树进行了决策之后x被选择,能获得的最大权值和,g(x)表示x子树进行了决策之后x没有被选进去,能够得到的最大权值和;

f(x)=(枚举)g(son)+valx,g(x)=(枚举儿子)max{f(son),g(son)}

考虑枚举顺序,先更新儿子。记忆化搜索

#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 6100
struct tree{
    int to,nx;
}edge[maxn];
int head[maxn],cnt,f[maxn],g[maxn],v[maxn],tag,max1;
void add(int u,int v)
{
    edge[++cnt].nx=head[u];
    edge[cnt].to=v;
    head[u]=cnt;
}
void dfs(int x)
{
    f[x]=v[x];
    for(int i=head[x];i;i=edge[i].nx)
    {
        if(edge[i].to!=x){
            dfs(edge[i].to);
            f[x]+=g[edge[i].to];
            g[x]+=max(g[edge[i].to],f[edge[i].to]);
        }
    }
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>v[i];
    for(int i=1;i<=n;i++)
    {
        int u,v;
        cin>>v>>u;
        if(i==n-1) tag=u;
        add(u,v);
    }
    dfs(tag);
    max1=max(g[tag],f[tag]);
    cout<<max1;
    return 0;
}

求树的重心(题目是以图的形式给的)

对于一根n个节点的无根树,找到一个点A,使得把树变成以该点为根的有根树时,最大子树的结点树最小。A叫做重心。

求一下每个点子树的点数,再考虑当其作为重心时,最大子树的结点数,和当前重心进行比较;

  1. 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个重心,他们的距离和一样。(我还感觉,重心作用:以重心为树根使得树的深度最小)
  2. 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
  3. 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
  4. 一棵树最多有两个重心,且相邻。

一般也可用作优化,使得最大子树大小不超过n/2

记忆搜索:
void
dfs(int x,int fa)//fa指的是x的父亲 { int t=0;siz[x]=1;//只有一个x节点时,长度为1 for(int i=head[x];i;i=edge[i].nx) { if(edge[i].to!=fa) { dfs(edge[i].to,x);//遍历每个子节点 siz[x]+=siz[edge[i].to]; t=max(t,siz[edge[i].to]);//t记录最大子树的结点数 }
  } t
=max(t,n-siz[x]); //比较fa另一侧的子树结点数与当前最大结点数 if(mx>t) { mx=t,poi=x; } }

树的直径

树的直径是树当中最长的一条链

void dfs(int x,int fa)//fa指的是x的父亲
{
    for(int i=head[x];i;i=edge[i].nx)
    {
        if(edge[i].to!=fa)
        {
            int v=edge[i].to;
            dfs(edge[i].to,x);//遍历每个子节点
            if(dp[0][v]+w[v]>dp[0][x])//dp[0][x]代表以0为节点的最长链,1为次长链            {
                dp[1][x]=dp[0][x];//进行更新,因为一个点只遍历一次,所以最长链上的节点与次长链上的结点不会重合
                dp[0][x]=dp[0][v]+w[v];
            }
            else if(dp[0][v]+w[v]>dp[1][x])
                dp[1][x]=dp[0][v]+w[v];
        } 
      
    }
   ans=max(ans,dp[1][x]+dp[0][x]);
   return;
}

 

posted @ 2020-02-26 13:37  SuccessfulRoad  阅读(156)  评论(0编辑  收藏  举报