zoukankan      html  css  js  c++  java
  • 树形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;
    }
  • 相关阅读:
    CSS 使用技巧
    CSS display
    CSS float
    .NET自动识别HttpWebResponse的编码及是否压缩
    通用权限管理系统基类中数据库的连接
    通用权限底层实现的记录软删除及表中应包含的基本字段
    最好用的兼容多种数据库通用高效的大数据分页功能
    水平权限漏洞的修复方案
    通用权限管理系统菜单展示的一个技巧
    IE11下用forms身份验证的问题
  • 原文地址:https://www.cnblogs.com/Showend/p/12359086.html
Copyright © 2011-2022 走看看