zoukankan      html  css  js  c++  java
  • 树形DP题目集合

    [树形DP](https://cn.vjudge.net/contest/123963#overview)


    #include<cstdio>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    #include<set>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<cctype>
    #include<stack>
    #include<sstream>
    #include<list>
    #include<assert.h>
    #include<bitset>
    #include<numeric>
    #define debug() puts("++++")
    #define gcd(a,b) __gcd(a,b)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define fi first
    #define se second
    #define pb push_back
    #define sqr(x) ((x)*(x))
    #define ms(a,b) memset(a,b,sizeof(a))
    #define sz size()
    #define be begin()
    #define pu push_up
    #define pd push_down
    #define cl clear()
    #define lowbit(x) -x&x
    #define all 1,n,1
    #define rep(i,x,n) for(int i=(x); i<=(n); i++)
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> P;
    const int INF = 0x3f3f3f3f;
    const LL LNF = 1e18;
    const int maxm = 1e6 + 10;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int dx[] = {-1,1,0,0,1,1,-1,-1};
    const int dy[] = {0,0,1,-1,1,-1,1,-1};
    int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int mod = 10056;
    #define inf 0x3f3f3f3f
    #define ll long long
    const int maxn = 1e5+5;
    int t,n,m,x,y;
    int dp[maxn][2],v[maxn],a[maxn];
    int head[maxn];
    struct node
    {
        int v,nxt;
    }e[maxn*2];
    
    int tot;
    void init()
    {
        tot=0;//!
        ms(head,-1);
        ms(dp,0);
        ms(v,0);
    }
    void add(int u,int v)
    {
        e[tot].v=v;
        e[tot].nxt=head[u];
        head[u]=tot++;
    }
    void dfs(int u,int fa)
    {
        //dp[u][0]=0;
        dp[u][1]=a[u];
        for(int i=head[u]; i!=-1; i=e[i].nxt)
        {
            int v = e[i].v;
            if(v == fa) continue;
            dfs(v,u);
            dp[u][0] += max(dp[v][0],dp[v][1]);
            dp[u][1] += dp[v][0];
        }
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            init();
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            for(int i=1;i<=n-1;i++)
            {
                scanf("%d%d",&x,&y);
                add(x,y);
                add(y,x);
                v[x]++;
            }
            scanf("
    0 0");
            int root;
            for(int i=1;i<=n;i++)
            {
                if(!v[i])
                {
                    root=i;
                    break;
                }
            }
            dfs(root,root);
            printf("%d
    ",max(dp[root][0], dp[root][1]));
        }
    }
    /*
    
    【题意】
    
    
    【类型】
    树形DP
    
    【分析】
    
    【时间复杂度&&优化】
    
    【trick】
    
    【数据】
    
    */
    A HDU 1520 Anniversary party
    #include<cstdio>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    #include<set>
    #include<queue>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<cctype>
    #include<stack>
    #include<sstream>
    #include<list>
    #include<assert.h>
    #include<bitset>
    #include<numeric>
    #define debug() puts("++++")
    #define gcd(a,b) __gcd(a,b)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define fi first
    #define se second
    #define pb push_back
    #define sqr(x) ((x)*(x))
    #define ms(a,b) memset(a,b,sizeof(a))
    #define sz size()
    #define be begin()
    #define pu push_up
    #define pd push_down
    #define cl clear()
    #define lowbit(x) -x&x
    #define all 1,n,1
    #define rep(i,x,n) for(int i=(x); i<=(n); i++)
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> P;
    const int INF = 0x3f3f3f3f;
    const LL LNF = 1e18;
    const int maxm = 1e6 + 10;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int dx[] = {-1,1,0,0,1,1,-1,-1};
    const int dy[] = {0,0,1,-1,1,-1,1,-1};
    int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int mod = 10056;
    #define inf 0x3f3f3f3f
    #define ll long long
    const int maxn = 1e4+5;
    int t,n,m,x,y,w,ans;
    int dp[maxn*2],v[maxn],a[maxn];
    int head[maxn];
    struct node
    {
        int v,w,nxt;
    }e[maxn*2];
    
    int tot;
    void init()
    {
        tot=0; //!
        ms(head,-1);
        ms(dp,0);
    }
    void add(int u,int v,int w)
    {
        e[tot].v=v;
        e[tot].w=w;
        e[tot].nxt=head[u];
        head[u]=tot++;
    }
    int dfs(int u,int fa)
    {
        int Max=0;
        for(int i=head[u]; i!=-1; i=e[i].nxt)
        {
            int v = e[i].v;
            if(v == fa) continue;
            if(!dp[i]) dp[i]=dfs(v,u)+e[i].w;
            Max=max(Max,dp[i]);
        }
        return Max;
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            init();
            for(int i=2;i<=n;i++) //!
            {
                scanf("%d%d",&y,&w);
                add(i,y, w),add(y,i, w);
            }
            for(int i=1;i<=n;i++)
                printf("%d
    ",dfs(i,-1));
        }
    }
    /*
    
    【题意】
    给出一颗树,求树中的每个顶点到其他所有顶点的最大值。
    
    【类型】
    树形DP,最短路
    
    【分析】
    题目给出10000个点,否则的话Floyd也是可以跑,但是给出的是一棵树,那么我们就可以用树形dp了
    1.(非两次DFS方法)
    每次从需要求的节点出发,然后遍历该树,期间更新该点的最长路。但是用DP数组存最长路的时候有一个问题,就是便利的方向,如果不考虑方向的话肯定是错的,那么可以转换一下,DP数组不存点的最长路,存边的最长路,这样使用邻接链表村边的化就可以考虑到方向了。具体看代码。
    2.(两次DFS方法)
    首先,我们分析发现,当前一个点的最大距离只有两种来源:
    一种是它到叶子节点的最大距离
    一种是经过根节点的最大距离(也就是根节点到叶子节点 不经过 当前点的最大距离 + 跟到当前点的距离)
    实现的话发现要求不经过当前点,所以我们求到叶子节点向上的最大距离时还要维护一个次短距离。
    
    首先一遍dfs,求出从任意一个节点到叶子节点的最短路dp[i][0]和次段路dp[i][1],算是一个预处理。
    然后,定义状态dp[i][2]从 i 点出发经过 root 节点的最短路。
    
    状态转移方程:
    dp[child][2] = max(dp[father][2],dp[child][0]+ child.cap == dp[father][0]?dp[father][1]:dp[father][0])+child.cap ;
    (PS:另一种方法可以在第一次dfs时把从叶子节点到根节点经过的点标记出来,然后在第二次更新的时候如果遇到是经过的点,然后直接选择次短路,可以尝试一下)
    
    【时间复杂度&&优化】
    
    【trick】
    dp数组必须开到1e5*2,否则TLE(不明觉厉???
    有两种做法。
    1、求树的直径。两遍dfs找到树的直径,根据树的直径的性质,从任意一个点出发走的最长距离,一定是到直径的端点。
    2、树形dp。也就是我写的做法。首先从根节点开始往下搜,每次跟新以这个节点为根节点的最远距离和次远距离。
    这样一次dfs之后,根节点的fir就是他所能达到的最远距离。
    然后从根开始往下搜,如果这个点的父亲节点的最远距离需要经过这个点,那么只需比较(父亲节点的次远距离+dis)和(自己这个点的最远距离),
    然后跟新这个点的次远和最远。如果不需要经过,那么比较 (父亲节点的最远距离+dis)和(自己这个点的最远距离),然后更新即可。
    
    【数据】
    
    */
    B - Computer HDU - 2196(法1
  • 相关阅读:
    G++与VS2015在变量作用域上的差异性
    SO_REUSEADDR与SO_REUSEPORT平台差异性与测试
    带着SMART原则重新出发
    动态语言的灵活性是把双刃剑 -- 以Python语言为例
    程序员必知的Python陷阱与缺陷列表
    MySQL添加字段和修改字段
    java poi给sheet表格中的某个单元格添加批注
    Maven入门:使用Nexus搭建Maven私服及上传下载jar包
    Linux上两种网络连接方式
    linux创建账户并自动生成主目录和主目录下的文件
  • 原文地址:https://www.cnblogs.com/Roni-i/p/9428071.html
Copyright © 2011-2022 走看看