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;
    }
  • 相关阅读:
    结巴分词 0.14 版发布,Python 中文分词库
    Lazarus 1.0.2 发布,Pascal 集成开发环境
    Android全屏 去除标题栏和状态栏
    服务器日志现 Android 4.2 传将添多项新特性
    Percona XtraBackup 2.0.3 发布
    长平狐 Android 强制设置横屏或竖屏 设置全屏
    NetBeans 7.3 Beta 发布,全新的 HTML5 支持
    CppDepend现在已经支持Linux
    GromJS 1.7.18 发布,服务器端的 JavaScript
    Apache OpenWebBeans 1.1.6 发布
  • 原文地址:https://www.cnblogs.com/Urchin-C/p/11681328.html
Copyright © 2011-2022 走看看