如何在多项式时间内解决最大团问题

如何在多项式时间内解决最大团问题

本篇文章将会教你如何随机化硬草 NP-Hard。

Solution A

最大团问题有一个非常直观、简洁、但是错误的贪心做法:每次贪心地往当前最大团内加点,能加就加,否则就无视。这种做法显然有可能找到最优解,但是显然更多情况下会错得离谱。

首先,我们需要尽可能避免加入的第一个点就不在最大团里的情况。方法是枚举一个必须在最大团里的点 \(u\),那么最大团里的其它点必须与 \(u\) 相邻,所以总共的枚举量是 \(O(\sum_u\operatorname{deg}(u))=O(m)\)。然后还需要判断加入一个新点后答案是否仍然为团,这里需要枚举当前团内的所有点。注意到最大团的点数不会超过 \(O(\sqrt m)\),所以总复杂度是 \(O(n+m\sqrt m)\)

但是这样仍然不太靠谱,因此我们设定一个求解次数 \(T\),将上述算法进行 \(T\) 次,但是每次都把点的出边顺序随机打乱,以此增加找到答案的概率。时间复杂度变成了 \(O(T(n+m\sqrt m))\)。在实践中,取 \(T=10\) 已经可以有相当的正确率,但更为精彩的是,我们曾经创下了 \(T=1\) 的 AC 纪录

概率分析:不会。

Solution B

下面的这种做法同样依赖于那个朴素的贪心和多次随机加点顺序,但是有更优秀的单次复杂度,却需要更多的随机次数,实测不如 Solution A 优秀。

发现在动态加点的过程中,如果一个点无法加入当前答案就放弃掉,会浪费掉大量的点。所以我们进行一种类似“多线程”的操作方式:同时维护多个备选答案。我们可以维护多个当前存在的最大团,新加入一个点 \(u\) 时,只会尝试加入最多 \(\operatorname{deg}(u)\) 个原本的答案。如果 \(u\) 向当前某个团 \(G\) 的连边数量等于团的大小 \(|G|\),就把 \(u\) 加入。可以用一个并查集维护这个过程,复杂度 \(O(T(n+m\alpha(n)))\),其中 \(T\) 是随机次数。

该做法有一个很不稳定的优化:每次尝试把 \(u\) 加入可以加入的大小最大的团。经过实验,这种优化有时候可以很快速地找到答案,但是在一些经过构造的数据中却用很多次随机都很难跑出答案,慎用。

概率分析:不会。

posted @ 2023-02-23 16:01  ExplodingKonjac  阅读(86)  评论(0编辑  收藏  举报