首页 > 其他分享 >LOJ #160. 树形背包 题解

LOJ #160. 树形背包 题解

时间:2024-08-27 23:37:44浏览次数:4  
标签:le LOJ 题解 kMaxN int 背包 dfs 物品 160

Description

有 \(N\) 个物品,编号分别为 \(1\ldots N\)。物品 \(i\) 的重量为 \(w_i\),价值为 \(v_i\)。

给出每个物品依赖于哪个物品。我们用 \(d_i = j\ (i>j>0)\) 表示:如果要选取物品 \(i\),就必须先选取物品 \(j\)。另外,我们用 \(d_i = 0 (i>0)\) 表示:该物品不依赖于任何物品。保证每个物品最多只依赖一个物品。保证依赖关系合理,不会出现环。

背包最多能装载的重量为 \(W\),请问背包中最多能装入多大价值的物品。

\(1\le N×W\le 6×10^7, 1\le N\le 5×10^4, 0\le W\le 6×10^4\)

\(1\le w_i\le 200,0\le v_i\le 5000\)

Solution

题目的限制相当于是要求出一个包含根的连通块使得重量之和不超过 \(W\),并且让价值之和最大。

可以设 \(f_{i,j}\) 表示 \(i\) 的子树里包含 \(i\) 的连通块重量之和为 \(j\) 的最大价值。容易做到 \(O(NW^2)\)。

上面那个做法慢在要做 \(N\) 次背包合并,单次背包合并就是 \(O(W^2)\) 的,所以要找到一个不需要背包合并的做法。

考虑按照 dfs 序从后往前 dp。

假设当前枚举到了 \(x\),则把 dfs 序大于等于 \(x\) 的点拿出来一定构成若干个子树,并且这些子树互不相交。如果在这些点中选出一些不存在依赖关系问题的点,那么每个子树一定选了一个包含根的连通块。

设 \(f_{i,j}\) 表示 dfs 序大于等于 \(i\) 的点构成重量和为 \(j\) 且不出现依赖关系问题的最大权值。

如果 \(i\) 选,则后面只要不存在问题,加入 \(i\) 后仍不出现问题,所以 \(f_{i,j}\leftarrow f_{i+1,j-w_i}+v_i\)。

如果 \(i\) 不选,则 \(i\) 的子树也不选,所以 \(f_{i,j}\leftarrow f_{i+sz_i,j}\)。

答案即为 \(\max_{0\leq i\leq W}\{f_{1,i}\}\)。

时间复杂度:\(O(NW)\)。

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 5e4 + 5, kMaxT = 6.1e7 + 5;

int n, m;
int p[kMaxN], w[kMaxN], v[kMaxN], pool[kMaxT];
int dfn[kMaxN], sz[kMaxN], idx[kMaxN];
std::vector<int> G[kMaxN];

void dfs(int u) {
  static int cnt = 0;
  idx[dfn[u] = ++cnt] = u, sz[u] = 1;
  for (auto v : G[u]) {
    dfs(v);
    sz[u] += sz[v];
  }
}

void dickdreamer() {
  std::cin >> n >> m;
  memset(pool, 0xcf, sizeof(pool));
  int (&f)[n + 2][m + 1] = decltype(f)(pool);
  for (int i = 1; i <= n; ++i) {
    std::cin >> p[i];
    if (p[i]) G[p[i]].emplace_back(i);
  }
  for (int i = 1; i <= n; ++i) std::cin >> w[i];
  for (int i = 1; i <= n; ++i) std::cin >> v[i];
  for (int i = 1; i <= n; ++i)
    if (!p[i])
      dfs(i);
  f[n + 1][0] = 0;
  for (int i = n; i; --i) {
    for (int j = m; ~j; --j) {
      f[i][j] = f[i + sz[idx[i]]][j];
      if (j >= w[idx[i]]) f[i][j] = std::max(f[i][j], f[i + 1][j - w[idx[i]]] + v[idx[i]]);
    }
  }
  std::cout << *std::max_element(f[1], f[1] + 1 + m) << '\n';
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  // std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:le,LOJ,题解,kMaxN,int,背包,dfs,物品,160
From: https://www.cnblogs.com/Scarab/p/18383739

相关文章

  • CF1810G The Maximum Prefix 题解
    Description构造一个长度最多为\(n\)的数组\(a\),其每个元素均为\(1\)或\(-1\)。生成方式如下:选择任意整数\(k\in[1,n]\)作为\(a\)的长度。对于\(\foralli\in[1,k]\),有\(p_i\)的概率设\(a_i=1\),有\(1-p_i\)的概率设\(a_i=-1\)。在数列被生成后,计算\(s_i=a......
  • NOI2024 D1T3 口胡题解
    NOI2024D1T3口胡题解题目条件其实就是说对于点对\((a,b)\),从\(a\)到\(b\)的路径上至少要有一条从\(b\)指向\(a\)​的边。将初始状态记作\((T,S)\)​,其中\(T\)​是树,\(S\)​是二元组\((a,b)\)​的集合。注意到特殊性质A蕴含了:如果对于所有二元组\((a,b)\),\(a......
  • [COCI2012-2013#1] SNAGA 题解
    前言题目链接:洛谷。题意简述定义\(f(x)\)表示不能整除\(x\)的最小正整数。给出数字\(n\),每次\(n\getsf(n)\),当\(n=2\)时停止。定义\(g(n)\)为这一过程中的数字个数,例如\(g(6)=4\)。给定\(l,r\),求\(\sum\limits_{i=l}^rg(i)\)。\(3\leql\ltr......
  • 【题解】「CQOI2014」通配符匹配
    【题解】「CQOI2014」通配符匹配https://www.luogu.com.cn/problem/P3167令\(s\)为模式串,\(t\)为文本串。首先有一个显然的的dp是,\(f_{i,j}\)表示模式串的前\(i\)个和文本串的前\(j\)个是否匹配。显然\(O(n^2)\)是过不了的。Motivation:注意到题目限定了通配符......
  • CF645D - Robot Rapping Results Report 题解
    \[Problem\]有\(N\)个机器人,给出\(M\)组关系,表示两个机器人的能力关系,问至少需要前几组关系可以确定所有机器人的排名。\[Solution\]由于是求最少的前几组关系,而关系越少越难确定排名,关系越多越容易确定,不难发现本题满足单调性,考虑二分。那么给出关系要求总排名的题,就应该......
  • AT_code_festival_2017_qualc_d - Yet Another Palindrome Partitioning 题解
    YetAnotherPalindromePartitioning题解题目大意给出一个字符串,求把这个字符串划分成最少的小段,使每个小段都可以经过字母重组后为回文串。题目分析如果暴力的话,需要DFS段数、每一段的左节点、右节点,以及判断是否为回文串,时间复杂度在\(O(|S|^{|S|})\)左右。但是本......
  • Dirsearch-master安装使用及常见问题解决(互联网和内网)
    1、文档概述        本手册适用于帮助初学者快速掌握Dirsearch-master的安装、配置与使用方法。通过阅读本文档,您将能够了解如何搭建Dirsearch-master环境、扫描目标服务器上潜在的敏感文件和目录,并解读生成的报告。此外,本文档还涵盖了常见问题及解决方法,以便您在实际......
  • 【题解】P3210 [HNOI2010] 取石头游戏
    \(\large\mathfrak{1st.\Preamble|}\)前言题目传送门:P3210[HNOI2010]取石头游戏)主要是参考楼下大佬的题解,对于其中没讲到或比较难懂的地方进行讲解,以及配上了图。\(\large\mathfrak{2nd.\Solution|}\)题解楼下大佬的比喻十分形象生动地描绘了俩人去石头的过程:取石子......
  • 题解:P10922 Happybob's Numbers (UBC001B)
    主要思路:贪心,构造。思路构造题,首先明确要删的就是小于\(n\)的数,因为若删了大于等于\(n\)的数就无法进行之后的操作了。那这道题就简单了,先从大到小排序,遇到小于当前长度\(k\)的数,就将这个数删掉,这时长度需减\(1\),毕竟顺序可以自己调,将下一个小于当前\(k\)的数,放到下一......
  • 题解:P5934 [清华集训2012] 最小生成树
    主要思路:网络流。思路先考虑最小生成树,如果一条边边权大于等于选中的边,那么这条边是否删去没有任何影响。按边权排序,对于边\((u,v,L)\),若要加上当且仅当\(u\)和\(v\)并不联通。把所有边权比选定的边的边权小的边拿出来连上,流量均为\(1\),最小割。最大树同理,连上边权比选......