簡體   English   中英

以排列值順序生成幾個列表的所有排列

[英]Generate All Permutations of Several Lists in Permutation-Value Order

我查看了有關排列的其他幾個問題,但似乎未出現此變體。 我正在尋找一種生成偏差排列的簡單方法。 這就是我的意思。

假設我有兩個列表(盡管我需要求解N個列表):

l1 = [a, b, c]
l2 = [d, e, f]

這些列表的排列看起來像[[(a,d),(a,e),(a,f),(b,d),(b,e),(b,f)...]。 但是,在我的世界中,對排列的元素進行了評分和求和,以評估這種安排。 假設ade得 2分, bcf得 1分。 然后,一些樣本排列的值是:

(a,d) = 4
(a,e) = 4 
(a,f) = 3
(c,f) = 2

我需要生成所有排列,但是我想先生成高值排列,然后再生成較低值的排列。

假設每個列表的元素按降序排列,是否有一種很好的方法可以按值順序生成排列?

(顯然,我可以生成所有排列並對它們進行排序,但是我寧願編寫一個生成器,因為排列的數量可能很大。)

使用簡單的貪婪風格算法,這應該很容易實現。 就是說,我假設您可以訪問特定的值,而不只是這些值的排序列表。 還假設它已排序。

l1 = [(a, 2), (b, 1), (c, 1)]
l2 = [(d, 2), (e, 2), (f, 1)]

事實是,這確實很重要,但是這是解決問題的方法(代碼可能稍后會出現,因為正如我所說,這實際上是很重要的。)

假設您在任何給定時間點有三種可能的操作:

  1. (next_values中最高(請參見下文),l1中l2的剩余項最高)
  2. (l1的當前項,l2的下一項)#假設您要遍歷l2
  3. (l1的下一個條目,l2的最高剩余條目)

然后,您必須隨時間跟蹤這三個值中的每個值,並在每個時間步長選擇最佳值。 這並不完全懶惰,因為您必須在每個時間步更新這三個值,這非常接近。

要實際實現這一點,我們必須保持一種數據結構:

next_entries: {*l1: last entry of l2 explored}
next_values: {*l1: l1 entry + next l2 entry}

此時,可以完成上述三個可能點的計算。 同樣,可以產生代碼,也許可以,但是以一種可讀的方式完成大約20行密集行。

例如,讓l1 = {6,4,3,1}和l2 = {5,4,1}。 將它們繪制為2D平面上的水平和垂直線。

繪圖和滑動線

那么興趣點都是交叉點。 我們應該報告這些交點,以使從(inf,inf)到(0,0)的假想掃掠線接觸它們。 請注意,水平線上的一個點不能比同一條線上的另一個點更早報告。 因此,對於每條水平線,我們必須僅檢查最右邊的點。 從所有這些點中,我們必須選擇一個坐標總和最大的坐標。 這可以通過堆數據結構來完成。

最初,我們將位於最右側垂直線上的所有點放入堆中。 然后,我們從堆中提取最高點,屈服,最后將其左鄰居放入堆中(如果有的話)。 因此,堆始終最多包含len(l1)個元素,並且每個新生成的點的成本為O(log(len(len(l1))))。 如果我們選擇l1作為給定的兩個最小列表,則可以改進解決方案。

這是示例解決方案:

import heapq

a = [("a", 6), ("b", 4), ("c", 3), ("d", 1)]
b = [("e", 5), ("f", 5), ("g", 4), ("h", 2)]

class Pair:
    def __init__(self, i, j, value):
        self.i = i
        self.j = j
        self.value = value
    def __cmp__(self, other):
        return other.value - self.value

def solution(a, b):
    heap = []
    for i in range(len(a)):
        heapq.heappush(heap, Pair(i, 0, a[i][1] + b[0][1]))
    while len(heap) > 0:
        pair = heapq.heappop(heap)
        yield (a[pair.i], b[pair.j], pair.value)
        if pair.j + 1 < len(b):
            heapq.heappush(heap, Pair(pair.i, pair.j + 1, a[pair.i][1] + b[pair.j + 1][1]))

for (a, b, value) in solution(a, b):
    print ("%s %s -> %d" % (a, b, value))

當我們進入更高的維度(要合並的列表超過2個)時,情況會變得更糟。 它可以在2D解決方案的基礎上通過備忘錄來解決,因此我們首先為l1,l2作為類似懶惰列表的數據結構建立答案,然后針對此備忘錄列表和l3作為參數再次應用相同的算法,等等。 必須采取的最后一步-我們要么總是使用長度較小的數組作為l1,要么擺脫一開始就將l1的所有元素都推入堆中。

N列表的完整代碼示例在這里 ,因為它太長了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM