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

    luogu

    树形DP从下往上把状态更新,既然需要从叶结点更新到根节点,所以需要先从根节点先深搜到叶结点,然后才能从树下端更新到树上端。

    三道模板很开心。

    P1352

    题意:舞会开始,一个人的上司来了,他就肯定不来........有向边 终点存在的话 那起点一定不存在, 求最多多少个点

    #include <stdio.h>
    #include <math.h>
    #include <algorithm>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    const int maxn = 6010;
    int n;
    int u, v;
    int r[maxn];
    vector<int> son[maxn];
    int dp[maxn][2];
    int vis[maxn];
    void Dp(int x) {
        dp[x][0] = 0;
        dp[x][1] = r[x];
        int len = son[x].size();
        for (int i = 0; i < len; i++) {
            Dp(son[x][i]);
            dp[x][0] += max(dp[son[x][i]][0], dp[son[x][i]][1]);
            dp[x][1] += dp[son[x][i]][0];
        }
    }
    int main () {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &r[i]);
        }
        while (scanf("%d%d", &u, &v) && (u || v)) {
            son[v].push_back(u);
            vis[u] = 1;
        }
        int rt;
        for (int i = 1; i <= n; i++) {
            if (vis[i] == 0) {
                rt = i;
                break;
            }
        }
    //    printf("rt = %d
    ", rt);
        Dp(rt);
        printf("%d
    ", max(dp[rt][1], dp[rt][0]));
        return 0;
    } 

    P2016

    和第一个差不多,不一样的地方在于双向边,边的起点和终点可以同时存在,求的是最少可以放多少个点

    #include <stdio.h>
    #include <algorithm>
    #include <math.h>
    
    using namespace std;
    
    const int maxn = 1510;
    const int inf = 1e9+7;
    struct node {
        int v, nxt;
    }edge[maxn * maxn];
    int head[maxn], tot;
    
    void Insert(int u, int v) {
        edge[++tot].v = v;
        edge[tot].nxt = head[u];
        head[u] = tot;
    }
    
    int n, m, u, v;
    int dp[maxn][2];
    void dfs(int u, int fa) {
        dp[u][0] = 0;
        dp[u][1] = 1;
        for (int i = head[u]; i; i = edge[i].nxt) {
    //        printf("u=%d fa=%d
    ", u, fa);
            int v = edge[i].v;
            if (v == fa) continue;
            dfs(v, u);
            dp[u][0] += dp[v][1];
            dp[u][1] += min(dp[v][0], dp[v][1]);
        }
    }
    int main () {
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &u, &m);
            for (int j = 0; j < m; j++) {
                scanf("%d", &v);
                Insert(u, v);
                Insert(v, u);
            }
        }
        dfs(0, -1);
        printf("%d
    ", min(dp[0][0], dp[0][1]));
        return 0;
    }

    P2014

    #include <stdio.h>
    #include <algorithm>
    
    typedef long long ll;
    using namespace std;
    #define lc(i) i<<1
    #define rc(i) i<<1|1
    const int maxn = 300+10;
    int N, M;
    int dp[maxn][maxn];
    int w[maxn];
    struct node {
        int v,nxt;
    }edge[maxn];
    int head[maxn], tot;
    void Insert(int u, int v) {
        edge[++tot].v = v;
        edge[tot].nxt = head[u];
        head[u] = tot;
    }
    void getmp() {
        int u, v;
        scanf("%d%d", &N, &M);
        for (int i = 1;i <= N; i++) {
            scanf("%d%d",&v, &dp[i][1]);
            Insert(v, i);
        }
    }
    void dfs(int u) {
        for (int i = head[u]; i; i = edge[i].nxt) {
            int v = edge[i].v;
            dfs(v);
            for (int j = M + 1; j; j--) {
                for (int k = 0; k < j; k++) {
                    dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k]);
                }
            }
        }
    }
    int main() {
        getmp();
        dfs(0);
        printf("%d
    ", dp[0][M+1]);
        return 0;
    }

    P2015

    树形dp + 01背包

    虚拟了0作为根节点,树枝变成了 一条边和终点  的形式

    1点之上没有边,只是人为虚拟出来的,背包的时候可以通过dp[1][0]来更新状态,而其他的点在深搜到之前就已经下放了边权值

    #include <stdio.h>
    #include <algorithm>
    #include <cstring>
    #include <math.h>
    
    using namespace std;
    
    const int maxn = 105;
    const int maxm = 3e4 + 10;
    const int inf = 1e9+7;
    
    struct node {
        int v, nxt, w;
    }edge[maxn * 2];
    int head[maxn], tot;
    
    void Insert(int u, int v, int w) {
        edge[++tot].v = v;
        edge[tot].w = w;
        edge[tot].nxt = head[u];
        head[u] = tot;
    }
    
    int n, m, u, v, w, q;
    int dp[maxn][maxn];
    void dfs(int u, int fa) {
        for (int i = head[u]; i; i = edge[i].nxt) {
            int v = edge[i].v, w = edge[i].w;
            if (v == fa) continue;
            dp[v][1] = w;
            dfs(v, u);
            for (int j = q; j; j--) {//开始背包了,子树的最优解现在可以看成是新的物品的价值,这里整体的感觉给我像是把诸多二叉树的状态整合成了一根链状的dp[v]的状态
                for (int k = 0; k <= j; k++) {//k == j 包含了dp[u][0] 不要以u为起点的边的情况 
                    if ((k != j && j != 1) || u == 1)//并没有搞明白这里是怎么一回事//那么为什么1这个结点如此特殊?
                        dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k]);
                }
            }
        }
    }
    int main () {
        scanf("%d%d", &n, &q);
        for (int i = 1; i < n; i++) {
            scanf("%d%d%d", &u, &v, &w);
            Insert(u,v,w);
            Insert(v,u,w);
        }
        dfs(1, 0);
        
        printf("%d
    ", dp[1][q]);
        return 0;
    }
  • 相关阅读:
    分页存储过程
    调存储过程
    winform httplicent调用API
    存储过程,触发器,等等。。。
    C# AJAXform上传图片
    Mysql order by与limit联用出现的问题
    将Sublime Text 3 放到右键中
    Vue-cli构建步骤
    Javascript面试知识点
    position详解
  • 原文地址:https://www.cnblogs.com/Urchin-C/p/11681328.html
Copyright © 2011-2022 走看看