最大团问题(Maximum Clique Problem, MCP)是图论中一个经典的组合优化问题,也是一类NP完全问题。看到前面的描述可能会觉得很复杂,但是最大团的定义其实很简单,通俗点讲最大团问题就是一个最大的完全子图的问题。
因为是NP完全问题,自然没有多项式时间复杂度求解的算法,解决这个问题有很多有效的算法:遗传算法、模拟退火算法、禁忌算法等等,但是这些算法比较高级,这里讲一种比较简单的搜索算法。
算法
概述
总体上来讲,这个算法就是通过DFS进行搜索,通过剪枝来优化的方法。DFS搜索的本质就是维护一个已经是完全图的子图,并在搜索过程中不断扩大这个子图,直到所有的点都被考虑进去。
DFS过程
初始化:
从一个点 u 开始,把这个点加入集合 U 中。将编号比它大的且和它相连的点加入集合 S1 中,为了方便,将集合 S1 中的点有序,让他们从小到大排列,进行第一遍 DFS
第一遍 DFS :
从 S1 中选择一个点 u1,遍历 S1 中,所有编号比 u1 大且和 u1 相连的点,其实也就是排在 u1 后面,并且和 u1 相连的点,将它们加入集合 S2 中。同理,让 S2 中的点也按照编号也从小到大排列。将 u1 加入集合 U 中,进行第二遍 DFS
第二遍 DFS :
从 S2 中选择一个点 u2,遍历 S2 中,所有排在 u2 后面且和 u2 相连的点,并把它们加入集合 S3 中,让 S3 中的点按照编号从小到大排列,将 u2 加入集合 U 中进行第三遍 DFS
第三遍 DFS :
从 S3 中选择一个点 u3,遍历 S3 中,所有排在 u3 后面且和 u3 相连的点,并把它们加入集合 S4 中,让 S4 中的点按照编号从小到大排列,将 u3 加入集合 U 中进行第四遍 DFS
……
最底层的 DFS :
当某个 S 集合为空时,DFS 过程结束,得到一个只用后面几个点构成的完全子图,并用它去更新只用后面几个点构成的最大团。退出当前 DFS,返回上层 DFS,接着找下一个完全子图,直到找完所有的完全子图
辅助集合
为每一层的DFS遍历开一个集合Sn,用来表示在这一层DFS中,考虑加入完全图中的点。从这个集合Sn中取一个点准备加入完全图,同时将和这个点相连的Sn中的其他点加入下一层DFS的辅助集合S(n+1)中去。
剪枝1
已经在完全图U中的点的数量 + 辅助集合Sn中的点的数量 < 已经产生的最优解,则不再进行后面的DFS
剪枝2
已经在完全图U中的点的数量 + 后面集合能够构成的最大完全子图的顶点数量 < 已经产生的最优解,则不再进行后面的DFS。
模板
1 |
|
ZOJ 1492
题意
裸的最大团模板题
代码
1 | nclude <iostream> |