满足条件的列表的排列?

时间:2018-07-27 00:00:58

标签: python python-3.x algorithm permutation

说我有一个图像列表['1.jpg', '2.jpg', '3.jpg'...]和一个对应的垂直尺寸列表[200, 400, 300...],我试图返回图像列表的所有排列,其中尺寸位于相邻元素的10%以内。事实证明,这非常具有挑战性!

我首先在整个列表上尝试了itertools.permutations,然后遍历每个元素并检查了有效性。这种方法有效,但是当n > 12变得很慢时,从一开始就生成如此多的无效排列似乎无效。

然后我意识到顺序并不是特别重要,因为图像将循环显示,因此我固定了列表中的第一个元素,但这仍然需要我对每个元素进行置换,因此效率低下。 / p>

然后我去寻找另一种方法,并决定尝试这种方法:

images = ['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg']
v_size = [100, 125, 110, 120, 95]
pairs = list(itertools.permutations(images,2))

这产生了所有可能的图像配对的列表,然后我可以对其进行验证和过滤,仅筛选出符合+/- 10%标准的对,因此最终我剩下了以下符合我的标准的有效配对:

[('1.jpg', '3.jpg'), ('1.jpg', '5.jpg'), ('2.jpg', '4.jpg'), ('3.jpg', '1.jpg'), ('3.jpg', '4.jpg'), ('4.jpg', '2.jpg'), ('4.jpg', '3.jpg'), ('5.jpg', '1.jpg')]

检查它似乎很有意义。因此,图像1和3可以彼此相邻放置,图像3和4、4和2等也可以放置在一起。因此,我要生成的是将这些图像重新组合以找到原始图像的所有(如果有)有效排列。例如:

['5.jpg', '1.jpg', '3.jpg', '4.jpg', '2.jpg']

将是有效的安排,而:

['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg']

不会,因为图像的大小在彼此的10%大小限制之外。

我已经考虑过递归,但是我对此很陌生,不确定从哪里开始。

如我已经尝试了几天,将不胜感激有关如何解决此问题的任何建议!

2 个答案:

答案 0 :(得分:3)

这是一个图形问题。每个节点的大小在10%以内的任何节点都具有双向边缘。在限制条件下找到所有排列与在该图中找到所有哈密顿路径都是同构的。

首先,您需要构建图形;使用您喜欢的图形包或更简单的表示。此预处理必须为 O(n ^ 2),因为边缘的数量可能为this.scanAlerts.filter((a) => ((a.alertType === null)。但是,在实际情况下,您可以先按大小对列表进行排序,这应该为您提供有效的 O(n log n)排序和 O(n)图形构建,因为从每个节点到它的邻居只有很少的连接。例如,在您给定的迷你示例中,我将添加另一个文件,因此我们有:

ScanAlertModel

从此处保留上限标记alertType

  • 从95开始;将边缘设为100。设置n(n-1)/2(索引为100)
  • 移动到100;使边缘达到102和110。# Before sorting images = ['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg', '6.jpg'] v_size = [100, 125, 110, 120, 95, 102] # After sorting images = ['5.jpg', '1.jpg', '6.jpg', '3.jpg', '4.jpg', '2.jpg'] v_size = [95, 100, 102, 110, 120, 125]
  • 移至102;不用检查就使边缘达到110;由于mark,我们已经知道它在范围内。检查是否太远120。
  • 移至110;优势上升到120 ...您可以从这里得到灵感。

然后您将查找可用于遍历图形的算法,即哈密顿路径。

答案 1 :(得分:0)

解决方案非常简单。首先,您对垂直尺寸进行排序,这样一来,您就可以更容易理解其原理(无需对所有尺寸进行相同的排序即可使用,但更难以调试或找出问题所在)。

排序后,您将构建一个矩阵,其中包含1用于图片之间的每个可能过渡,否则包含0

然后,这是简单的详尽的递归搜索,以查找行之间的可能跳转:

import numpy as np

v_size = [95, 100, 102, 110, 120, 125]

ss = sorted(v_size)
num = len(v_size)

sq = np.zeros([num,num]).astype(int)

for i in range(num) :
    for j in range(num) :
        if i == j : continue

        if abs(ss[i]-ss[j]) < (ss[i]+ss[j])/20.0 :  # 10%
            sq[i,j] = sq[j,i] = 1

print sq

current = []

def search( row ) :
    if len(current) == num :
        print current
        return
    for i in range(num) :
        if sq[row,i] > 0 and i not in current :
            current.append(i)
            search(i)
            current.pop()
    return

for i in range(num) :
    current.append(i)
    search(i)
    current.pop()

首先打印出此连接矩阵,然后打印出可能的序列。

'''
[[0 1 1 0 0 0]
 [1 0 1 1 0 0]
 [1 1 0 1 0 0]
 [0 1 1 0 1 0]
 [0 0 0 1 0 1]
 [0 0 0 0 1 0]]

[0, 1, 2, 3, 4, 5]
[0, 2, 1, 3, 4, 5]
[1, 0, 2, 3, 4, 5]
[2, 0, 1, 3, 4, 5]
[5, 4, 3, 1, 0, 2]
[5, 4, 3, 1, 2, 0]
[5, 4, 3, 2, 0, 1]
[5, 4, 3, 2, 1, 0]
'''

对于10%的公差,有8个结果,对于20%的公差,有96个结果(此处未打印,因为它长约100行=)。