前言
关于最大独立集以及本博客内贪心算法的思想见本人的另一篇博客,这里实现的是贪心算法3.
代码实现
import random
import networkx as nx
import matplotlib.pyplot as plt
# 创建图
def create_graph(V,E):
G = nx.Graph()
G.add_nodes_from(V)
G.add_edges_from(E)
# 将生成的图 G 打印出来
pos = nx.circular_layout(G)
options = {
"with_labels": True,
"font_size": 20,
"font_weight": "bold",
"font_color": "white",
"node_size": 2000,
"width": 2
}
nx.draw_networkx(G, pos, **options)
ax = plt.gca()
ax.margins(0.20)
plt.axis("off")
plt.show()
return G
# 获取图G内顶点的度以及其邻居节点
def get_info(V,E):
G = create_graph(V,E)
Adj_matrix = nx.adjacency_matrix(G)
# 转换为二维数组矩阵
A = Adj_matrix.todense()
# 通过访问邻接矩阵获取图内每个顶点的度以及其邻居节点,并将信息存储到字典info内
info = {}
for i in range(len(A)):
# 统计节点的度
node = 0
# 统计节点的邻居节点
adj = []
for j in range(len(A)):
if j <= len(V):
node += A.item(i,j)
if A.item(i,j) == 1:
adj.append(j)
print('节点{}的度为{},邻居信息为{}'.format(V[i],node,adj))
info[i] = adj
print('当前图G内各顶点的度以及邻居顶点信息为{}'.format(info))
# 返回图内信息
return info
# 计算顶点i的支撑
def s(i,info):
m = 0
# 获取顶点i的邻居
neibor = info[i]
if len(neibor) == 0:
m = 0
# print('顶点{}为孤立点,支撑为0'.format(i))
else:
# 计算顶点i邻居节点的支撑(度之和)
for j in range(0,len(neibor)):
m += len(info[neibor[j]])
return m
# 向顶点子集I内添加节点a
def step1(info,I):
# 统计每个节点的度
node = []
for key,value in info.items():
# 需要注意的是,列表node中默认无重复元素
node.append(len(value))
# 寻找最小度
min_node = min(node)
# 最小度的顶点,存储到列表node_set中
node_set = []
for i in range(0,len(info)):
if len(info[i]) == min_node:
node_set.append(i)
# 初始化顶点子集I为空集,首选向I内添加度最小的顶点
if len(node_set) == 1:
I.append(node_set[0])
a = node_set[0]
else:
# 计算node_set内元素的支撑,对应信息存储到列表k内,选择最大支撑
k = []
info1 = {}
for j in range(0,len(node_set)):
# 调用计算支撑的函数
k.append(s(node_set[j],info))
# 将顶点j以及其支撑存储到字典info1中
info1[node_set[j]] = s(node_set[j],info)
# 获取最大支撑的数值
max_k = max(k)
print('当前最小度顶点有:{},对应的支撑为{}'.format(node_set,k))
# 将支撑度最大的顶点信息存储到列表q内
q = []
for key,value in info1.items():
if value == max_k:
q.append(key)
# 将度最小,支撑最大的顶点加入到I中
if len(q) == 1:
I.append(q[0])
a = q[0]
else:
# 随机生成0-len(q)中的整数
t = random.randint(0,len(q)-1)
print('当前支撑度最大的顶点有:{},随机生成数为:{}'.format(q,t))
I.append(q[t])
a = q[t]
return a,I
# 更新图G,从图G内删除顶点i和顶点i的邻居节点,以及相关联的边。
def step2(i,info):
# 获取顶点i的邻居节点信息
neigor = info[i]
# 将顶点i从图G中删除,V1内存储删除i后的其余节点
V1 = []
for m in range(0,len(V)):
if V[m] != i:
V1.append(V[m])
# 将顶点i的邻居节点从图G中删除
for j in range(0,len(neigor)):
V2 = []
for m in range(0,len(V1)):
if V1[m] != neigor[j]:
V2.append(V1[m])
V1 = V2
# 删除和顶点i相关联的边
update_E1 = []
for j in range(0,len(E)):
if i not in E[j]:
update_E1.append(E[j])
# 删除和顶点i的邻居节点相关联的边
for j in range(0,len(neigor)):
update_E = []
for k in range(0,len(update_E1)):
if neigor[j] not in update_E1[k]:
# 保证边集内无重复元素
if update_E1[k] not in update_E:
update_E.append(update_E1[k])
# 更新当前的边集
update_E1 = update_E
# 返回更新后的顶点集合以及边集
return V1,update_E1
# 主函数
V = [0,1,2,3,4]
E = [(0, 1), (1, 2),(2,3),(3,4),(0,4)]
initial_I = []
while len(E)!=0:
#获取当前图G信息
info = get_info(V,E)
# 将顶点a加入到I内
a,I = step1(info,initial_I)
print('当前的独立集I = {}'.format(I))
# 更新图G
V,E = step2(a,info)
print('更新后的图G,V={},E= {}'.format(V,E))
print('\n')
initial_I = I
if len(E) == 0:
# 将零图内的顶点加入到I内
for i in range(0,len(V)):
I.append(V[i])
print('利用贪心算法得到的近似解为:{}'.format(I))
上述代码中涉及如何根据邻接矩阵获取图G内每个顶点的度以及邻居节点,如何从图G内删除指定顶点以及与指定顶点相关联的边。我以一个5顶点的2正则图运行了上述代码,效果如下:
如有错误,欢迎指正~