【回溯】最大团问题Python实现
个人主页:丷从心
系列专栏:回溯法
问题描述
-
给定无向图 G = ( V , E ) G = (V , E) G=(V,E),如果 U ? V U \subseteq V U?V,且对任意 u u u, v ∈ U v \in U v∈U有 ( u , v ) ∈ E (u , v) \in E (u,v)∈E,则称 U U U是 G G G的完全子图
-
G G G的完全子图 U U U是 G G G的一个团当且仅当 U U U不包含在 G G G的更大的完全子图中, G G G的最大团是指 G G G中所含顶点数最多的团
-
如果 U ? V U \subseteq V U?V且对任意 u u u, v ∈ U v \in U v∈U,有 ( u , v ) ? E (u , v) \notin E (u,v)∈/E,则称 U U U是 G G G的空子图
-
G G G的空子图 U U U是 G G G的独立集当且仅当 U U U不包含在 G G G的更大的空子图中, G G G的最大独立集是 G G G中所含顶点数最多的独立集
-
对于任意无向图 G = ( V , E ) G = (V , E) G=(V,E),其补图 G ˉ = ( V ′ , E ′ ) \bar{G} = (V^{'} , E^{'}) Gˉ=(V′,E′)定义为: V ′ = V V^{'} = V V′=V, E ′ = { ? ( u , v ) ∣ ( u , v ) ? E ? } E^{'} = \set{(u , v) \mid (u , v) \notin E} E′={(u,v)∣(u,v)∈/E}
-
如果 U U U是 G G G的完全子图,则它是 G ˉ \bar{G} Gˉ的空子图,反之亦然,因此, G G G的团与 G ˉ \bar{G} Gˉ的独立集之间存在一一对应关系,特别地, U U U是 G G G的最大团,当且仅当 U U U是 G ˉ \bar{G} Gˉ的最大独立集
-
无向图 G G G和 G G G的补图 G ˉ \bar{G} Gˉ如下图所示
回溯法
- 图 G G G的最大团和最大独立集问题都可以看作图 G G G的顶点集 V V V的子集选取问题,因此,可用子集树表示问题的解空间,解最大团问题的回溯法与解装载问题的回溯法十分相似
- 设当前扩展结点 Z Z Z位于解空间树的第 i i i层,在进入左子树前,必须确认从顶点 i i i到已选入的顶点集中每个顶点都有边相连,在进入右子树前,必须确认还有足够多的可选择顶点,使得算法有可能在右子树中找到更大的团
时间复杂性
- 解最大团问题的回溯算法所需的计算时间为 O ( n 2 n ) O(n 2^{n}) O(n2n)
Python
实现
def find_maximum_clique(graph):
n = len(graph)
vertices = list(range(n))
max_clique = []
def is_clique(graph, vertices):
# 约束函数: 判断给定的顶点集合是否构成一个团(完全子图)
for i in range(len(vertices)):
for j in range(i + 1, len(vertices)):
if not graph[vertices[i]][vertices[j]]:
return False
return True
def bound(current_clique, neighbors):
# 限界函数
return len(current_clique) + len(neighbors)
def backtrack(graph, vertices, current_clique, max_clique):
if not vertices:
if len(current_clique) > len(max_clique):
max_clique.clear()
max_clique.extend(current_clique)
return
vertex = vertices.pop(0)
current_clique.append(vertex)
neighbors = []
for v in vertices:
if graph[vertex][v]:
neighbors.append(v)
# 选择当前顶点并加入团
if is_clique(graph, current_clique):
backtrack(graph, neighbors, current_clique, max_clique)
# 不选择当前顶点
if bound(current_clique, neighbors) > len(max_clique):
backtrack(graph, neighbors, current_clique[:-1], max_clique)
vertices.insert(0, vertex)
current_clique.pop()
backtrack(graph, vertices, [], max_clique)
return max_clique
graph = [
[0, 1, 0, 1, 1],
[1, 0, 1, 0, 1],
[0, 1, 0, 0, 1],
[1, 0, 0, 0, 1],
[1, 1, 1, 1, 0]
]
maximum_clique = find_maximum_clique(graph)
print(f'最大团: {maximum_clique}')
最大团: [0, 1, 4]
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!