Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 图的完全子图划分算法_Python_Algorithm_Graph_Data Science - Fatal编程技术网

Python 图的完全子图划分算法

Python 图的完全子图划分算法,python,algorithm,graph,data-science,Python,Algorithm,Graph,Data Science,我需要一个算法来将一个无向图的顶点划分成一个或多个子图,这样每个子图都是一个完整的图(每个顶点与其他每个顶点相邻)。每个顶点需要正好位于一个子图中 下面是一个例子: 输入=[ (A、B), (B、C), (A、C), (B、D), (D,E), ] 输出=myalgo(输入)#[(A、B、C)、(D、E)] 下面是一幅更好地描述问题的图像: 输入列表按距离按降序排序,这就是我连接A-B-C而不是B-D的原因 我认为这可能被称为“强连接组件”,并且已经尝试了以下解决方案: 字体它在寻找不同的

我需要一个算法来将一个无向图的顶点划分成一个或多个子图,这样每个子图都是一个完整的图(每个顶点与其他每个顶点相邻)。每个顶点需要正好位于一个子图中

下面是一个例子:

输入=[
(A、B),
(B、C),
(A、C),
(B、D),
(D,E),
]
输出=myalgo(输入)#[(A、B、C)、(D、E)]
下面是一幅更好地描述问题的图像:

输入列表按距离按降序排序,这就是我连接A-B-C而不是B-D的原因

我认为这可能被称为“强连接组件”,并且已经尝试了以下解决方案:

  • 字体它在寻找不同的东西

  • :它给了我很多周期,但不是最好的,它不关心输入顺序

  • :它连接所有组件,只是因为它们之间有一条路径(a-B-C-D-E)

  • :它仅适用于有向图


警告:这取决于dict在python 3.7+中保持插入顺序这一事实。在旧版本中,您必须使用
matrix=DefaultOrderedDict(dict)

以下是一个类,它将分段实现为完整的子图。它绝对不是优化的,可能会得到显著改进,但这只是一个起点

类SCCManager:
定义初始(自,边):
self.clusters=[]
self.edges=边
def集群_输入(自身,连接):
第一,第二=康涅狄格州
f_clust=无
s_clust=无
对于i,枚举中的clust(self.clusters):
如果是第一个:
f_clust=i
如果第二个在集群中:
s_clust=i
#如果两者都已找到,则提前中断
如果f_clust和s_clust:
打破
返回(f_clust,s_clust)
def all_已连接(自身、群集、顶点):
对于集群中的v:
已连接=(v,顶点)在self.edges中或(顶点,v)在self.edges中
#如果任何元素未连接到候选元素,请提前中断
如果未连接:
返回错误
返回真值
def get_scc(自我):
对于self.edges中的边:
c_first,c_second=self.clusters_in(边)
#情况1:所有顶点都不在现有簇中
#->创建包含顶点的新簇
如果c_first==c_second==None:
self.clusters.append([edge[0],edge[1]])
持续
#案例2:第一个在集群中,第二个不在集群中
#->如果符合条件,则添加到群集
如果你先来无和c_second==无:
#检查第二个是否已连接到所有群集组件
okay=self.all_connected(self.clusters[c_first],edge[1])
#如果符合条件,则添加到集群
如果可以:
self.clusters[c_first].append(边[1])
持续
#案例3:反过来
如果c_first==无,c_second!=无:
okay=self.all_connected(self.clusters[c_second],edge[0])
如果可以:
self.clusters[c_second].append(边[0])
持续
#案例4:两者都在不同的集群中
#->如果允许,合并群集
如果你先来c_秒:
#检查集群是否可以合并
对于self.clusters中的v[c_first]:
merge=self.all_connected(self.clusters[c_second],v)
#如果未连接任何图元,则中断
如果不合并:
打破
#如果允许,合并
如果合并:
self.clusters[c_-first].extend(self.clusters[c_-second])
self.clusters.remove(self.clusters[c_second])
#案例5:两者都在同一集群中
#如果输入是正常的,则不会发生,但无论哪种方式都不需要操作
返回self.clusters
。。。下面是一个有效的例子:

inp=[
(‘A’、‘B’),
('B','C'),
('A','C'),
('B','D'),
('D','E'),
(‘C’、‘E’)
]
测试=SCCManager(inp)
打印(test.get_scc())
[A',B',C',[D',E']]
另一次尝试:

lst = [
    ('A', 'B'),
    ('B', 'C'),
    ('A', 'C'),
    ('B', 'D'),
    ('D', 'E'),
]

d = {}
for i, j in lst:
    d.setdefault(i, []).append(j)
    d.setdefault(j, []).append(i)

from itertools import combinations

rv, seen_segments, seen_vertices = [], set(), set()
for k, v in d.items():
    if len(v) == 1:
        segment = set((k, v[0])).difference(seen_vertices)
        seen_vertices.update(segment)
        rv.append([tuple(segment), ])
    else:
        graph = []
        for i, j in combinations([k] + v, 2):
            if not j in d[i]:
                break
            else:
                graph.append(tuple(sorted((i, j))))
        else:
            if graph:
                graph = [segment for segment in graph if segment not in seen_segments]
                seen_segments.update(graph)
                if graph:
                    rv.append(graph)

from pprint import pprint
pprint(rv)
印刷品:

[[('A', 'B'), ('A', 'C'), ('B', 'C')], [('D', 'E')]]
[[('A', 'B')], [('C',)]]
[[('B', 'A')], [('D', 'C')]]

输入

lst = [
    ('A', 'B'),
    ('B', 'C'),
]
印刷品:

[[('A', 'B'), ('A', 'C'), ('B', 'C')], [('D', 'E')]]
[[('A', 'B')], [('C',)]]
[[('B', 'A')], [('D', 'C')]]

输入:

lst = [
    ('A', 'B'),
    ('B', 'C'),
    ('C', 'D'),
]
印刷品:

[[('A', 'B'), ('A', 'C'), ('B', 'C')], [('D', 'E')]]
[[('A', 'B')], [('C',)]]
[[('B', 'A')], [('D', 'C')]]

您可以找到所有路径,然后按连接进行分组:

from itertools import groupby as gb
d = [('A', 'B'), ('B', 'C'), ('A', 'C'), ('B', 'D'), ('D', 'E')]
def connect_num(node):
    return [sum(a == node for a, _ in d), sum(b == node for _, b in d)]

def group_paths(data):
   new_d = sorted([[i, connect_num(i)] for i in data], key=lambda x:max(x[1]))
   return [[k for k, _ in b] for _, b in gb(new_d, key=lambda x:max(x[1]))]

def get_paths(start, c = [], seen = []):
   new_vals = [a for a, _ in d if a not in seen+c]
   if (vals:=[b for a, b in d if a == start]):
      for i in vals:
         yield from get_paths(i, c=c+vals, seen=seen)
   else:
      yield c
      for i in new_vals:
         yield from get_paths(i, c = [i], seen=c+seen)

result = sorted(map(set, get_paths(d[0][0])), key=len, reverse=True)
new_result = [a for i, a in enumerate(result) if not any(all(k in c for k in a) for c in result[:i])]
final_result = [group_paths(i) for i in new_result]
输出:

#final_result[0]
[['E', 'D'], ['A', 'C', 'B']]

“强连接”的意思是“组件中的所有元素都必须相互直接链接”@Lukastaller yesSounds就像一个有趣的练习。让我看看我能想出什么:D矩阵是个好主意,但是如果我在输入中添加另一个('C','E'),算法就会崩溃。我认为更新逻辑需要更健壮一点,以处理更复杂的输入。如果您提供了完全错误的输入,因为我对它进行了测试,它在当前输入的末尾对('C','E')有效。
inp=[('a','B','C'),('a','C'),('B','D','D'),('D','E'),('C','E')]
结果是
[{'B','C','a','E','D','E','C'}]
用于3.7版本的meRunning。这个输入的输出是什么?是的,你是对的:P.我在为矩阵中的顶点运行修改版
。keys():
,这是我回答中的另一个选项。我修改了第一个,使用了正确的逻辑。假设输入是一个大集团,去掉了一条边。正确答案是分离缺失边顶点的所有顶点分区。您喜欢哪一种?这取决于用户输入。OP在他们的问题中提到边缘在物质中的顺序。如果上面的图中的(b,d)边是第一个输入的,我们将得到组件(a,c)和(b,d),(和(e),如果你想考虑一个组件,我现在的实现没有这样的组件)