网页链接:http://bbit.vip/service/main.php?version=1&type=article&id=118
亲爱的读者朋友大家好,上次我们分析了如何用一个亚线性时间算法估计一个点集合的直接,并对算法给出的结果的近似比进行了分析。这次我们来看另外一个经典的问题,求连通分量的数目。
同样地,还是让我们先来看一下问题的定义:
定义:
已知: G = ( V , E ) , ϵ , d = d e g ( G ) G = (V,E),\epsilon,d = deg(G) G=(V,E),ϵ,d=deg(G),图 G G G用邻接表表示,其中 d d d表示所有节点中度最大的节点的度, ∣ V ∣ = n , ∣ E ∣ = m ≤ d ⋅ n |V| = n,|E| = m \leq d\cdot n ∣V∣=n,∣E∣=m≤d⋅n
求出:一个 y y y,使得 C − ϵ ⋅ n ≤ y ≤ C + ϵ ⋅ n C - \epsilon \cdot n \leq y \leq C + \epsilon \cdot n C−ϵ⋅n≤y≤C+ϵ⋅n,其中 C C C为使用线性算法求解得到的标准解
问题分析:
当数据量小的时候,我们也有经典的算法进行求解,也就是经典的搜索策略,时间复杂度为 O ( n ) O(n) O(n),其中 n n n是节点的个数,还是老问题,当节点数目太多的时候,就需要一个亚线性时间复杂度的算法对结果进行一个近似的估计。
在正式分析算法之前,我们先将问题进行一定的转化:记顶点 v v v所属的连通分量中的节点数目为 n v n_v nv, A , A ∈ V A,A \in V A,A∈V是一个连通分量的点集合,则存在如下等式关系: ∑ u ∈ A 1 n u = ∑ u ∈ A 1 ∣ A ∣ = 1 \sum_{u \in A}{\frac{1}{n_u}} = \sum_{u \in A}{\frac{1}{|A|}} = 1 ∑u∈Anu1=∑u∈A∣A∣1=1,这个很容易证明,因为同一个连通分量中的每一个点的 1 n v \frac{1}{n_v} nv1是一样的,都是分量中点的个数的倒数。如此,则最终的结果 C C C可以表示为 ∑ u ∈ V 1 n u \sum_{u \in V}{\frac{1}{n_u}} ∑u∈Vnu1。因此进一步地,对 C C C的估计可以转化为对 1 n u \frac{1}{n_u} nu1的估计。
求解问题的思想:
n u n_u nu很大,精确计算很难,但是此时 1 n u \frac{1}{n_u} nu1很小,可以用一个很小的常量代替 1 n u ( 0 \frac{1}{n_u}(0 nu1(0或者 ϵ 2 ) \frac{\epsilon}{2}) 2ϵ),如果我设 n u ^ = m i n { n u , 2 ϵ } \hat{n_u} = min\{n_u,\frac{2}{\epsilon}\} nu^=min{nu,ϵ2},则 C ^ = ∑ u ∈ V 1 n u ^ \hat{C} = \sum_{u \in V}{\frac{1}{\hat{n_u}}} C^=∑u∈Vnu^1,使用 C ^ \hat{C} C^来估计 C C C可以获得很不错的结果。
引理:
∀ u ∈ V \forall u \in V ∀u∈V,有 ∣ 1 n u − 1 n u ^ ∣ ≤ ϵ 2 |\frac{1}{n_u} - \frac{1}{\hat{n_u}}| \leq \frac{\epsilon}{2} ∣nu1−nu^1∣≤2ϵ,即 ∣ C − C ^ ∣ ≤ ϵ ⋅ n 2 |C - \hat{C}| \leq \frac{\epsilon \cdot n}{2} ∣C−C^∣≤2ϵ⋅n
引理的证明非常简单,分成两步,第一步证明 ∣ 1 n u − 1 n u ^ ∣ ≤ ϵ 2 |\frac{1}{n_u} - \frac{1}{\hat{n_u}}| \leq \frac{\epsilon}{2} ∣nu1−nu^1∣≤2ϵ,第二步证明 ∣ C − C ^ ∣ ≤ ϵ ⋅ n 2 |C - \hat{C}| \leq \frac{\epsilon \cdot n}{2} ∣C−C^∣≤2ϵ⋅n
证明(一): 1 n u ^ = m a x { 1 n u , ϵ 2 } \frac{1}{\hat{n_u}} = max\{\frac{1}{n_u},\frac{\epsilon}{2}\} nu^1=max{nu1,2ϵ}。如果 1 n u > ϵ 2 \frac{1}{n_u}>\frac{\epsilon}{2} nu1>2ϵ, 1 n u ^ = 1 n u ⇒ 1 n u ^ − 1 n u = 0 ⇒ ∣ 1 n u ^ − 1 n u ∣ = 0 ≤ ϵ 2 \frac{1}{\hat{n_u}} = \frac{1}{n_u} \Rightarrow \frac{1}{\hat{n_u}} - \frac{1}{n_u} = 0 \Rightarrow |\frac{1}{\hat{n_u}} - \frac{1}{n_u}| = 0 \leq \frac{\epsilon}{2} nu^1=nu1⇒nu^1−nu1=0⇒∣nu^1−nu1∣=0≤2ϵ;如果 1 n u ≤ ϵ 2 \frac{1}{n_u}\leq \frac{\epsilon}{2} nu1≤2ϵ, ∣ 1 n u ^ − 1 n u ∣ = ∣ ϵ 2 − 1 n u ∣ < ϵ 2 |\frac{1}{\hat{n_u}} - \frac{1}{n_u}| = |\frac{\epsilon}{2} - \frac{1}{n_u}| < \frac{\epsilon}{2} ∣nu^1−nu1∣=∣2ϵ−nu1∣<2ϵ
证明(二): ∣ C − C ^ ∣ = ∣ ∑ u ∈ V 1 n u ^ − ∑ u ∈ V 1 n u ∣ = ∣ ∑ u ∈ V ( 1 n u ^ − 1 n u ) ∣ ≤ ∑ u ∈ V ∣ 1 n u ^ − 1 n u ∣ = ϵ ⋅ n 2 |C - \hat{C}| = |\sum_{u \in V}{\frac{1}{\hat{n_u}}} - \sum_{u \in V}{\frac{1}{n_u}}| = |\sum_{u \in V}{(\frac{1}{\hat{n_u}} - \frac{1}{n_u}})| \leq \sum_{u \in V}|{\frac{1}{\hat{n_u}} - \frac{1}{n_u}}| = \frac{\epsilon \cdot n}{2} ∣C−C^∣=∣∑u∈Vnu^1−∑u∈Vnu1∣=∣∑u∈V(nu^1−nu1)∣≤∑u∈V∣nu^1−nu1∣=2ϵ⋅n
算法-计算 n u ^ \hat{n_u} nu^
思想很简单,就是一个小型的搜索,如果搜索到的点的个数小于 2 ϵ \frac{2}{\epsilon} ϵ2就继续搜索,否则直接返回 2 ϵ \frac{2}{\epsilon} ϵ2。时间复杂度为 O ( d ⋅ 1 ϵ ) O(d\cdot \frac{1}{\epsilon}) O(d⋅ϵ1), d d d越大,用的时间越长, 1 ϵ \frac{1}{\epsilon} ϵ1 越大,用的时间越长。
算法-计算 n u n_u nu
从节点集合中随机选出 r = b / ϵ 2 r = b/{\epsilon}^2 r=b/ϵ2个节点构成节点 U U U,对每个节点应用上一个算法,于是最终的 C ^ = n r ∑ u ∈ U 1 n u ^ \hat{C} = \frac{n}{r} \sum_{u \in U}{\frac{1}{\hat{n_u}}} C^=rn∑u∈Unu^1,时间复杂度为 O ( d / ϵ 3 ) O(d/{\epsilon}^3) O(d/ϵ3)
算法评价
计算连通分量的数目是一个较为简单的问题,下次介绍最小生成树的求解,敬请期待~