zoukankan      html  css  js  c++  java
  • 树形背包小结

    已知(2+1)?种做法

    分别是:

    • 按dfs序倒推

    Link

    BZOJ2427代码

    int sta[N], dfn[N], low[N], w[N], val[N], dp[N][505], n, m, top, W[N], V[N], fa[N], l[N], cnt[N], siz[N], bel[N], idx;
    vint G[N];
     
    bitset<N>ins, vis;
    void tarjan(int u) {
      static int tar = 0, idx = 0;
      ins[sta[++top] = u] = 1, dfn[u] = low[u] = ++idx;
      for (vint::iterator v = G[u].begin(); v != G[u].end(); ++v) {
        if (!dfn[*v]) {
          tarjan(*v);
          low[u] = min(low[u], low[*v]);
        }
        else if (ins[*v]) low[u] = min(low[u], dfn[*v]);
      }
      if (dfn[u] == low[u]) {
        int v; ++tar;
        do {
          ++cnt[tar];
          ins[v = sta[top--]] = 0, bel[v] = tar;
          w[tar] += W[v], val[tar] += V[v];
        }
        while (u != v);
      }
    }
    void dfs(int u) {
      l[++idx] = u, siz[u] = 1;
      for (vint::iterator v = G[u].begin(); v != G[u].end(); ++v) dfs(*v), siz[u] += siz[*v];
    }
     
    void init() {
     
    }
     
    void solve() {
      in, n, m;
      lo1(i, n) in, W[i];
      lo1(i, n) in, V[i];
      lo1(i, n) G[fa[i] = in].pb(i);
      lo1(i, n) if (!dfn[i]) tarjan(i);    
      lo0(i, n + 1) G[i].clear();
      lo1(i, n)
      if (cnt[bel[i]] > 1 && !vis[bel[i]]) G[0].pb(bel[i]), vis[bel[i]] = 1; else if (cnt[bel[i]] == 1) G[bel[fa[i]]].pb(bel[i]);
      dfs(0);
      memset(dp, 0xbf, sizeof dp);
      dp[idx + 1][0] = 0;
      dl1(i, idx) {
        int x = l[i];
        lo0(j, m + 1) {
          chmax(dp[i][j], max(dp[i + siz[x]][j], 0));
          if (w[x] <= j) chmax(dp[i][j], dp[i + 1][j - w[x]] + val[x]);
        }
      }
      int ans = 0;
      lo1(i, m) chmax(ans, dp[1][i]);
      out, ans;
    }
     
    int main() {
    #ifdef QvvQ
      // freopen("data.in", "r", stdin);
      // freopen("data.out", "w", stdout);
      Dbg = 1;
    #endif
      int T = 1;
      while (T--) init(), solve();
    #ifdef QvvQ
      fprintf(stderr, "
    time:%.5fms", clock() * 1000.0 / CLOCKS_PER_SEC);
    #endif
      return 0;
    }
    
    • 2009集训队论文中的写法

    dp(u res)表示选择了根到u的路径上的所有点 再在u左侧(已经遍历过的部分)和u的子树内选择重量最大为res的物品的最大价值

    BZOJ2427代码

     w[N], val[N], dp[N][505], n, m, top, W[N], V[N], fa[N], cnt[N], bel[N];
    vint G[N];
     
    bitset<N>ins, vis;
    void tarjan(int u) {
      static int tar = 0, idx = 0;
      ins[sta[++top] = u] = 1, dfn[u] = low[u] = ++idx;
      for (vint::iterator v = G[u].begin(); v != G[u].end(); ++v) {
        if (!dfn[*v]) {
          tarjan(*v);
          low[u] = min(low[u], low[*v]);
        }
        else if (ins[*v]) low[u] = min(low[u], dfn[*v]);
      }
      if (dfn[u] == low[u]) {
        int v; ++tar;
        do {
          ++cnt[tar];
          ins[v = sta[top--]] = 0, bel[v] = tar;
          w[tar] += W[v], val[tar] += V[v];
        }
        while (u != v);
      }
    }
    void DP(int u, int res) {
      if (!res) return ;
      for (vint::iterator it = G[u].begin(); it != G[u].end(); ++it) {
        copy(dp[u] + 1, dp[u] + 1 + res, dp[*it] + 1);
        DP(*it, res >= w[*it] ? res - w[*it] : res);
        dl(j, res, w[*it]) chmax(dp[u][j], dp[*it][j - w[*it]] + val[*it]);
      }
    }
     
    void init() {
     
    }
     
    void solve() {
      in, n, m;
      lo1(i, n) in, W[i];
      lo1(i, n) in, V[i];
      lo1(i, n) G[fa[i] = in].pb(i);
      lo1(i, n) if (!dfn[i]) tarjan(i); 
      lo0(i, n + 1) G[i].clear();
      lo1(i, n)
      if (cnt[bel[i]] > 1 && !vis[bel[i]]) G[0].pb(bel[i]), vis[bel[i]] = 1; else if (cnt[bel[i]] == 1) G[bel[fa[i]]].pb(bel[i]);
      DP(0, m - w[0]);
      out, dp[0][m] + val[0];
    }
     
    int main() {
    #ifdef QvvQ
      // freopen("data.in", "r", stdin);
      // freopen("data.out", "w", stdout);
      Dbg = 1;
    #endif
      int T = 1;
      while (T--) init(), solve();
    #ifdef QvvQ
      fprintf(stderr, "
    time:%.5fms", clock() * 1000.0 / CLOCKS_PER_SEC);
    #endif
      return 0;
    }
    

    另一种在dfs过程中枚举 i <- siz[u] to 0j <- 0 to siz[v]的做法 (好像跟上面两种不通用,如果通用求指正)

    一个这个写法的题目

  • 相关阅读:
    .NET开发相关使用工具和框架
    Jquery.KinSlideshow 焦点图标轮换
    可能发生了架构损坏。请运行 DBCC CHECKCATALOG。
    mssql使用问题大合集
    做饭流程js
    点击导航切换和隐藏
    批量修改文件名后缀
    GB2312转码utf-8字符方法
    border三角形的3种方式
    移动端nav导航栏
  • 原文地址:https://www.cnblogs.com/storz/p/10446892.html
Copyright © 2011-2022 走看看