我有双向飞行的搜索结果。因此,有两个列表包含出发航班和抵达航班,例如:
所以,我将在出发航班和到达航班之间有600(20 * 30)组合。我将组合列表称为结果列表
但是,我只想从600组合中选择限制。例如,我将选择最佳的100个航班组合。结合航班的标准是出发和到达航班的便宜价格。
为此,我将按出发和到达航班的总价格对结果列表进行排序。然后我从结果列表中获取前100个元素以获得我想要的内容。
但是,如果出发航班列表有200个航班,并且到达航班列表有300个航班,我将拥有结果列表,有60.000个元素。因此,我将对包含60.000个元素的列表进行排序,以找到最佳的100个元素。
因此,有任何算法可以选择最佳组合作为我的情况。
非常感谢你。
答案 0 :(得分:4)
您的问题并非100%明确,但我了解您正在寻找更快的算法来查找一定数量的最佳/最便宜的出发和到达航班组合。
您可以通过单独按成本对出发和到达航班列表进行分类,然后使用heap逐个扩展下一个最佳组合,直到快得多 你有足够的。
这里是完整的算法 - 在Python中,但没有使用任何特殊的库,只是标准的数据结构,所以这应该可以很容易地转移到任何其他语言:
NUM_FLIGHTS, NUM_BEST = 1000, 100
# create test data: each entry corresponds to just the cost of one flight
from random import randint
dep = sorted([randint(1, 100) for i in range(NUM_FLIGHTS)])
arr = sorted([randint(1, 100) for i in range(NUM_FLIGHTS)])
def is_compatible(i, j): # for checking constraints, e.g. timing of flights
return True # but for now, assume no constraints
# get best combination using sorted lists and heap
from heapq import heappush, heappop
heap = [(dep[0] + arr[0], 0, 0)] # initial: best combination from dep and arr
result = [] # the result list
visited = set() # make sure not to add combinations twice
while heap and len(result) < NUM_BEST:
cost, i, j = heappop(heap) # get next-best combination
if (i, j) in visited: continue # did we see those before? skip
visited.add((i, j))
if is_compatible(i, j): # if 'compatible', add to results
result.append((cost, dep[i], arr[j]))
# add 'adjacent' combinations to the heap
if i < len(dep) - 1: # next-best departure + same arrival
heappush(heap, (dep[i+1] + arr[j], i+1, j))
if j < len(arr) - 1: # same departure + next-best arrival
heappush(heap, (dep[i] + arr[j+1], i, j+1))
print result
# just for testing: compare to brute-force (get best from all combinations)
comb = [(d, a) for d in dep for a in arr]
best = sorted((d+a, d, a) for (d, a) in comb)[:NUM_BEST]
print best
print result == best # True -> same results as brute force (just faster)
大致如下:
dep
和抵达航班arr
进行排序
(dep[0] + arr[0], 0, 0)
visited
设置dep
和下一个arr
获取相同的航班,从dep
获取相同的航班,从arr
获取相同的航班,即{{1} }和(dep[i+1] + arr[j], i+1, j)
这是一个非常小的工作示例。轴是(dep[i] + arr[j+1], i, j+1)
和dep
个航班的(成本),表中的条目采用arr
形式,其中n(c)m
是条目的迭代次数添加到n
(如果有的话),heap
是费用,而c
是它被添加到前10名&#39;的迭代次数。 m
列表(如果有)。
result
请注意矩阵的列和行中的总和如何总是增加,因此最好的结果始终可以在左上角的某个三角形区域中找到。现在的想法是,如果你当前最好的组合(堆中的第一个组合)是dep\arr 1 3 4 6 7
2 0(3)1 1(5)4 4(6)8 8(8)- -
2 1(3)2 2(5)6 6(6)9 9(8)- -
3 2(4)3 3(6)7 7(7)- - -
4 3(5)5 5(7)- - - -
6 5(7)10 - - - -
Result: (1,2), (1,2), (1,3), (3,2), (1,4), (3,2), (3,3), (2,4), (2,4), (1,6)
,那么检查没有用,例如,组合dep[i], arr[i]
之前检查dep[i+2], arr[i]
,它必须具有较低的总成本,因此您将dep[i+1], arr[i]
(以及同样dep[i+1], arr[i]
)添加到堆中,并重复从堆中弹出下一个元素。
我将此算法的结果与您的蛮力方法的结果进行了比较,结果飞行是相同的,即算法有效,总是产生最佳结果。复杂性应该是 O(n log(n)),用于对出发和到达列表进行排序( n 是这些原始列表中的航班数量),加上 O (m log(m))用于堆循环( m 迭代, log(m)每次迭代工作, m 是结果列表中的元素数量。)
这可以找到 100,000 出发和 100,000 到达航班的最佳 1,000 组合(总计 1,000,000,000,000 不到一秒的可能组合。
请注意,这些号码是针对您没有其他限制的情况,即每个出发航班可以与每个到达航班组合。如果存在约束,您可以使用上面代码中勾画的dep[i], arr[i+1]
函数来检查这些并跳过该配对。这意味着,对于总成本较低的每个不兼容对,循环需要一次额外的迭代。这意味着在最坏情况中,例如,如果根本没有兼容的对,或者当唯一兼容的对是总成本最高的对时,算法可以事实上,扩展所有组合。
但平均而言,情况并非如此,算法的执行速度应该相当快。
答案 1 :(得分:1)
我认为最好的解决方案是使用一些SQL语句来做笛卡尔积。您可以根据数据本身,排序,范围选择等应用任何类型的过滤器。如下所示:
SELECT d.time as dep_time, a.time as arr_time, d.price+a.price as total_price
FROM departures d, arrivals a
WHERE a.time > d.time + X
ORDER BY d.price+a.price
LIMIT 0,100
实际上X
甚至可以为0,但到达后应该会在出发后到达。
为什么我会选择SQL: