zoukankan      html  css  js  c++  java
  • 【动态规划】树上背包

    https://codeforces.com/contest/1281/problem/F

    题意:每个顶点有两个权值b和w。最多3000个节点的树,分成恰好m个非空的连通块,使得尽可能多的连通块满足w的和严格大于b的和。

    树上背包的套路题,这里背包 (dp[i][j]) 表示以i为根的子树,已经划分了 (j) 个连通块,包括根节点在内的最后一个连通块没有划分,能取到的最优值。

    这一题最优值看起来有两维,但是事实上是一个pair,假如在子树中已经取得了x个连通块“优势区”,那么即使子树中包含根节点在内的是负无穷的“暂时优势”,都比x-1个优势区和正无穷的暂时优势好(因为转移出x个连通块还会额外划分一个连通块,并不是转移到同一个值)。

    注意树上背包的siz是最后才加进循环里。

    在计算过程中,尚未计算完成的u子树中的dp,不能急着把根节点划分出新的块,要在计算完成后统一加上去。

    
    const int MAXN = 3000 + 10;
    
    int n, m;
    vector<int> G[MAXN];
    int w[MAXN], b[MAXN];
    
    int siz[MAXN];
    vector<pil> dp[MAXN];
    
    pil add(pil A, pil B) {
        A.first += B.first;
        A.second += B.second;
        return A;
    }
    
    void dfs(int u, int p) {
        siz[u] = 1;
        dp[u] = vector<pil>(siz[u] + 1, pil(-INF, -LINF));
        dp[u][0] = pil(0, w[u] - b[u]);
        vector<pil> tmp;
        for (int v : G[u]) {
            if (p == v)
                continue;
            dfs(v, u);
            tmp = dp[u];
            dp[u] = vector<pil>(siz[u] + siz[v] + 1, pil(-INF, -LINF));
            for (int i = 0; i <= siz[u] && i <= m; ++i) {
                for (int j = 0; j <= siz[v] && i + j <= m; ++j)
                    cmax(dp[u][i + j], add(tmp[i], dp[v][j]));
            }
            siz[u] += siz[v];
        }
        for (int i = min(siz[u] - 1, m - 1); i >= 0; --i)
            cmax(dp[u][i + 1], pil(dp[u][i].first + (dp[u][i].second > 0), 0LL));
    }
    

    https://codeforces.com/gym/102992/problem/M

    打掉一个怪兽要先打掉他的父亲,打一个怪兽的消耗是这个怪兽的hp和其存活的儿子们的hp的和。事先使用i次激光能打到的最小消耗。

    const int MAXN = 2000 + 10;
    
    int n;
    vector<int> G[MAXN];
    int a[MAXN];
    
    int siz[MAXN];
    vector<ll> dp[MAXN][2];
    
    void dfs(int u, int p) {
        siz[u] = 1;
        dp[u][0] = vector<ll>(siz[u] + 1, LINF);
        dp[u][1] = vector<ll>(siz[u] + 1, LINF);
        dp[u][0][0] = a[u], dp[u][1][1] = 0;
        vector<ll> tmp[2];
        for (int v : G[u]) {
            if (v == p)
                continue;
            dfs(v, u);
            tmp[0] = dp[u][0], tmp[1] = dp[u][1];
            dp[u][0] = vector<ll>(siz[u] + siz[v] + 1, LINF);
            dp[u][1] = vector<ll>(siz[u] + siz[v] + 1, LINF);
            for (int i = 0; i <= siz[u]; ++i) {
                for (int j = 0; j <= siz[v]; ++j) {
                    cmin(dp[u][0][i + j], tmp[0][i] + min(dp[v][0][j] + a[v], dp[v][1][j]));
                    cmin(dp[u][1][i + j], tmp[1][i] + min(dp[v][0][j], dp[v][1][j]));
                }
            }
            siz[u] += siz[v];
        }
    }
    

    https://codeforces.com/contest/815/problem/C

    dp[u][0][i]:在u子树中,不使用优惠券购买i个物品的最小价格
    dp[u][1][i]:在u子树中,使用优惠券购买i个物品的最小价格

    const int MAXN = 5000 + 10;
    
    int n;
    vector<int> G[MAXN];
    int c[MAXN], d[MAXN];
    
    int siz[MAXN];
    vector<int> dp[MAXN][2];
    
    void dfs(int u, int p) {
        siz[u] = 1;
        dp[u][0] = vector<int>(siz[u] + 1, INF);
        dp[u][1] = vector<int>(siz[u] + 1, INF);
        dp[u][0][0] = 0, dp[u][0][1] = c[u], dp[u][1][1] = d[u];
        vector<int> tmp[2];
        for (int v : G[u]) {
            if (v == p)
                continue;
            dfs(v, u);
            tmp[0] = dp[u][0], tmp[1] = dp[u][1];
            dp[u][0] = vector<int>(siz[u] + siz[v] + 1, INF);
            dp[u][1] = vector<int>(siz[u] + siz[v] + 1, INF);
            for (int i = 0; i <= siz[u]; ++i) {
                for (int j = 0; j <= siz[v]; ++j) {
                    cmin(dp[u][0][i + j], tmp[0][i] + dp[v][0][j]);
                    cmin(dp[u][1][i + j], tmp[1][i] + min(dp[v][0][j], dp[v][1][j]));
                }
            }
            siz[u] += siz[v];
        }
    }
    

    vector写法空间复杂度会节省非常多(最坏情况仍可以节省一半),由于空间压缩所节省的cache也会使得运行速度提升。

  • 相关阅读:
    一些qml资料
    qml 的又一个框架
    qml 最新资源
    sql 创建数据库
    sql2008 无法附加数据库
    C#==>匿名方法
    sql alter表字段处理
    哪些字符需要urlencode编码?具体怎么处理?
    vs2010设置编辑器背景颜色
    nbtstat -a <IP> 会显示主机名、所在工作组等信息
  • 原文地址:https://www.cnblogs.com/purinliang/p/14471415.html
Copyright © 2011-2022 走看看