numpy 从数组列表中查找唯一代表(元素)列表

ztmd8pv5  于 2023-10-19  发布在  其他
关注(0)|答案(3)|浏览(83)

我有一个由n数组组成的列表(或数组)。每个数组携带从0n-1的任意整数子集(数组中的数字不重复)。n=3的例子是:

l = [np.array([0, 1]), np.array([0]), np.array([1, 2])]

我想从每个数组中选择一个数字作为它的代表,这样就没有两个数组有相同的代表,并以与数组相同的顺序列出它们。换句话说,为数组选择的数字必须是唯一的,并且整个代表集将是数字0n-1的排列。对于上面的列表,它将是唯一的:

representatives = [1, 0, 2]

有一个保证,这样的代表名单存在我们的名单,但我们如何找到他们。如果有多个可能的代表名单,则可以随机选择其中任何一个。

rnmwe5a2

rnmwe5a21#

你所要求的是二分图的最大匹配,它的左集和右集分别由你的数组和它们的唯一元素索引。
networkx模块知道如何找到这样的最大匹配:

import numpy as np
import networkx as nx
import operator as op

def make_example(n,density=0.1):
    rng = np.random.default_rng()
    M = np.unique(np.concatenate([rng.integers(0,n,(int(n*n*density),2)),
                                  np.stack([np.arange(n),rng.permutation(n)],
                                           axis=1)],axis=0),axis=0)
    return np.split(M[:,1],(M[:-1,0] != M[1:,0]).nonzero()[0])

def find_matching(M):
    G = nx.Graph()
    m = len(M)
    n = 1+max(map(max,M))
    G.add_nodes_from(range(n,m+n), biparite=0)
    G.add_nodes_from(range(n),biparite=1)
    G.add_edges_from((i,j) for i,r in enumerate(M,n) for j in r)
    return op.itemgetter(*range(n,m+n))(nx.bipartite.maximum_matching(G))

范例:

>>> M = make_example(10,0.4)
>>> M
[array([0, 4, 8]), array([9, 3, 5]), array([7, 1, 3, 4, 5, 7, 8]), array([9, 0, 4, 5]), array([9, 0, 1, 3, 5]), array([6, 0, 1, 2, 8]), array([9, 3, 5, 7]), array([8, 1, 2, 5]), array([6]), array([7, 0, 1, 4, 6])]
>>> find_matching(M)
(0, 9, 5, 4, 1, 2, 3, 8, 6, 7)

这可以在几秒钟内完成数千个元素:

>>> M = make_example(10000,0.01)
>>> t0,sol,t1 = [time.perf_counter(),find_matching(M),time.perf_counter()]
>>> print(t1-t0)
3.822795882006176
t2a7ltrp

t2a7ltrp2#

这就是你要找的吗

def pick_one(a, index, buffer, visited):
    if index == len(a):
        return True
    for item in a[index]:
        if item not in visited:
            buffer.append(item)
            visited.add(item)
            if pick_one(a, index + 1, buffer, visited):
                return True
            buffer.pop()
            visited.remove(item)
    return False

a = [[0, 1], [0], [1, 2]]
buffer = []
pick_one(a, 0, buffer, set())
print(buffer)

输出量:

[1, 0, 2]
o2rvlv0m

o2rvlv0m3#

你可以使用flow network,这是你怎么做的:
1.你有k个从0到n-1的任意整数子集,你把它们连接到接收器。
1.所有数字1到n-1都连接到源。
1.这些数字连接到相关子集(num_i连接到子集k_i)。
1.图的所有权重都被初始化为1。
在构建流网络之后,你使用已知的算法如Edmonds–Karp algorithm或其他来找到最大流,这给予你O(m^2*n)的时间复杂度。
原因如下:
1.从源到数字有一条路径,从子集到接收器有一条路径,所以你不能从同一个子集中选择相同的数字两次。
1.当该算法在流网络中找到最大流时,其原则是使用所有连接到源的子集。

相关问题