zoukankan      html  css  js  c++  java
  • 关于树上背包复杂度的证明

    众所周知,树上背包如果上下界都卡紧了复杂度会是 \(O(nm)\),下面来进行这一点的证明。

    以下设节点总数为 \(n\),背包容量最大是 \(m\)

    合并两个泛化背包的复杂度为 \(O(s_1s_2)\),其中 \(s_1\) 是第一个泛化背包的容量,\(s_2\) 是第二个背包的容量,但这个复杂度是在背包容量不设上限的情况下。

    而在树上背包中,容量是有上限的。做树上背包的过程,实际上就是把 \(n\) 个节点合并到一个背包的过程,显然,合并的总次数是 \(O(n)\) 的。

    合并过程的时间复杂度显然只跟 \(s_1,s_2,m\) 有关系,其中 \(s_1,s_2\le m\),代表的含义是两个背包分别的容量。不难发现,合并这两个背包的复杂度应该是 \(O(\min(s_1+s_2,m)\times \min(s_1,s_2))\),之所以有这两个式子是因为我们首先枚举最终的背包的容量是多大,然后枚举较小背包放多少个。

    在实际操作中,我们不需要比较哪个背包较小,我们只需要给下界设置一个合适的值,设 \(i\) 为枚举的最终背包容量,\(j\) 是当前背包放多少个,只需要设置一个下界让 \(i-j\) 满足不超过另一个背包的值即可。不难发现这和直接枚举较小背包容量是等价的。

    我们对 \(s_1\)\(s_2\) 的大小进行分类讨论。

    \(s_1=m,s_2=m\) 容易发现这样的合并不会超过 \(\frac{n}{m}\) 次,这是因为两边背包容量都等于 \(m\),说明有很多超过 \(m\) 个点被考虑进的背包内,因为我们的最终目标是把所有点合并成一个背包,而合并超过 \(m\) 个点的背包不超过 \(\frac{n}{m}\) 个,原命题得证。由此,这里的复杂度是 \(O(nm)\) 的。

    \(s_1<m,s_2<m\)\(s_1+s_2\ge m\) 这种情况下的合并次数不会超过 \(\frac{n}{m}\),因为这相当于把大小小于 \(m\) 的子树全部合并,最坏情况是合并到不存在大小小于 \(m\) 的子树,由大小大于等于 \(m\) 的子树个数不会超过 \(\frac{n}{m}\) 可以知道合并次数不会超过 \(\frac{n}{m}\) 由此可知复杂度不会超过 \(O(nm)\)

    \(s_1<m,s_2<m\)\(s_1+s_2< m\) 我们考虑一下 \(m\) 个点合并成为一棵大小为 \(m\) 的树,总的复杂度应该为 \(m^2\),总共这样的树的个数不会超过 \(\frac{n}{m}\) 个,故最终的复杂度也应该为 \(O(nm)\)。由这段证明我们也可以得到所谓背包大小为 \(m\),实际上是一个限制,其标明整个树形背包的复杂度不会超过 \(O(n^2)\),当然大多数情况下我们认为 \(m<n\)

    由此可以得出,树上背包的复杂度为 \(O(nm)\)

  • 相关阅读:
    C++实现高斯滤波器
    移动通信
    最简单的DLL
    C/C++ 编译和链接过程
    Servlet 详解
    对 Java 集合的巧妙利用
    Java 泛型
    Java 字符编码与解码
    HTTP 400 错误
    a 标签的四种样式
  • 原文地址:https://www.cnblogs.com/TianMeng-hyl/p/15758923.html
Copyright © 2011-2022 走看看