zoukankan      html  css  js  c++  java
  • 0x54 树形DP

    树形DP我只知道千万别写森林转二叉树慢的要死

    没有上司的舞会 水!裸!

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    struct node
    {
        int x,y,next;
    }a[6100];int len,last[6100];
    void ins(int x,int y)
    {
        len++;
        a[len].x=x;a[len].y=y;
        a[len].next=last[x];last[x]=len;
    }
    
    int f[6100][2],h[6100];
    void treedp(int x)
    {
        f[x][0]=0;f[x][1]=h[x];
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            treedp(y);
            f[x][0]+=max(f[y][0],f[y][1]);
            f[x][1]+=f[y][0];
        }
    }
    
    int fa[6100];
    int main()
    {
        int n,x,y;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&h[i]);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            ins(y,x);fa[x]=y;
        }
        
        int rt;
        for(int i=1;i<=n;i++)
            if(fa[i]==0)rt=i;
        treedp(rt);
        printf("%d
    ",max(f[rt][0],f[rt][1]));
        return 0;
    }
    没有上司的舞会

     

    选课 带个背包咯,注意一下背包别重复用一个子节点就好

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    struct node
    {
        int x,y,next;
    }a[310];int len,last[310];
    void ins(int x,int y)
    {
        len++;
        a[len].x=x;a[len].y=y;
        a[len].next=last[x];last[x]=len;
    }
    
    int f[310][310],h[310],tot[310];
    void treedp(int x)
    {
        f[x][1]=h[x];tot[x]=1;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            treedp(y);
            for(int i=tot[x];i>=1;i--)
                for(int j=tot[y];j>=1;j--)    
                    f[x][i+j]=max(f[x][i+j],f[x][i]+f[y][j]);
            tot[x]+=tot[y];
        }
    }
    
    int fa[310];
    int main()
    {
        int n,m,x,y;
        scanf("%d%d",&n,&m);
        h[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&fa[i],&h[i]);
            ins(fa[i],i);
        }
        memset(f,-1,sizeof(f));
        treedp(0);
        printf("%d
    ",f[0][m+1]);
        return 0;
    }
    选课

    poj3585 这题还挺有意思哈,书上说这是“不定根”的树形DP问题,有个很高大上的名词叫二次扫描与换根法

    其实自己YY一下,设1为根,第一次dfs把每个点管辖的子树的流量d算出来,对于一个点其实它的流量就是这个d值+从父节点流出去的流量,画个图还是很好解决的,就是min(到父节点的边权,父节点的d值-当前点给父节点的贡献)

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    struct node
    {
        int x,y,c,next;
    }a[410000];int len,last[210000];
    void ins(int x,int y,int c)
    {
        len++;
        a[len].x=x;a[len].y=y;a[len].c=c;
        a[len].next=last[x];last[x]=len;
    }
    
    bool checkleaf(int x,int fr)
    {
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=fr)return false;
        }
        return true;
    }
    
    int d[210000];
    void dfs(int x,int fr)
    {
        d[x]=0;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=fr)
            {
                dfs(y,x);
                if(checkleaf(y,x)==true)d[x]+=a[k].c;
                else d[x]+=min(a[k].c,d[y]);
            }
        }
    }
    int mmax;
    void solve(int x,int fr,int rd)
    {
        mmax=max(mmax,d[x]+rd);
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=fr)
            {
                int g;
                if(checkleaf(y,x)==true)g=d[x]-a[k].c;
                else g=d[x]-min(a[k].c,d[y]);
                
                if(checkleaf(x,y)==true)solve(y,x,a[k].c);
                else solve(y,x,min(rd+g,a[k].c));
            }
        }
    }
    
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int n,x,y,c;
            scanf("%d",&n);
            len=0;memset(last,0,sizeof(last));
            for(int i=1;i<n;i++)
            {
                scanf("%d%d%d",&x,&y,&c);
                ins(x,y,c);ins(y,x,c);
            }
            dfs(1,0);
            mmax=0;solve(1,0,0);
            printf("%d
    ",mmax);
        }
        return 0;
    }
    poj3585

     

  • 相关阅读:
    【C#语言规范版本5.0学习】2 词法结构(一、简述)
    【C#语言规范版本5.0学习】1.11 特性
    TP5.1 实现超时未支付订单自动关闭
    tp5.1使用队列
    开启队列时,命令行输入php think queue:listen出现乱码
    mysql 查询分组后的总条数
    处理mysql先排序在分组
    mysql 5.7 sql_mode设置 坑
    Windows 版 SourceTree 免登录跳过初始设置的方法和下载地址
    thinkphp5.1-jwt的安装与使用
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/9457600.html
Copyright © 2011-2022 走看看