python - 蛮力算法牛运输的问题
问题描述
我正在研究优化问题,但遇到了作业问题。我必须编写一个蛮力算法来最小化飞船旅行的次数。问题是:外星人创造了一种新型的奶牛,现在他们想用最少的旅行次数把它运回来。每次行程的最大值为 10 吨。
这个练习提供了一些东西,比如这个算法来获取一个列表的所有可能的分区:
# From codereview.stackexchange.com
def partitions(set_):
if not set_:
yield []
return
for i in range(2**len(set_)//2):
parts = [set(), set()]
for item in set_:
parts[i&1].add(item)
i >>= 1
for b in partitions(parts[1]):
yield [parts[0]]+b
def get_partitions(set_):
for partition in partitions(set_):
yield [list(elt) for elt in partition]
输入是奶牛的字典,例如:cows = {'Jesse': 6,'Maybel': 3, 'Callie': 2, 'Maggie': 5},键是奶牛的名字和该值是母牛的重量(以吨为单位)。
输出必须是列表列表,其中每个内部列表代表一次旅行,例如:[['Jesse', 'Callie'], ['Maybel', 'Maggie']]
我的问题是:如何使用 get_partitions() 实现这个算法?DFS 是解决这个问题的好方法吗?
我已经尝试了很多方法,但是我在 stackoverflow 找到了其中两种方法,似乎更接近答案:
使用 get_partitions() 函数获得所有可能的组合,并选择所有符合
limit = 10
列表内部的组合。就像我在这里看到的:为什么这种蛮力算法会产生不正确的结果?但它不起作用,因为它返回一个空列表。然后我尝试了深度优先搜索,就像我在这里看到的一样,有一些变化:如何从所有蛮力组合中找到最佳解决方案?并且列表还没有返回正确的答案。
这是我从正确答案中得到的最接近的结果。首先,我使用 get_partitions 生成所有可能的分区,然后我将分区过滤到一个名为 possible 的列表中,其中仅包含行程,limit <= 10
并且行程中包含所有奶牛(排除那些只有一个或两个奶牛名称的分区)。
def brute_force_cow_transport(cows,limit=10):
"""
Finds the allocation of cows that minimizes the number of spaceship trips
via brute force. The brute force algorithm should follow the following method:
1. Enumerate all possible ways that the cows can be divided into separate trips
Use the given get_partitions function in ps1_partition.py to help you!
2. Select the allocation that minimizes the number of trips without making any trip
that does not obey the weight limitation
Does not mutate the given dictionary of cows.
Parameters:
cows - a dictionary of name (string), weight (int) pairs
limit - weight limit of the spaceship (an int)
Returns:
A list of lists, with each inner list containing the names of cows
transported on a particular trip and the overall list containing all the
trips
"""
possible_combinations = []
for partition in get_partitions(cows.keys()):
possible_combinations.append(partition)
possible_combinations.sort(key=len)
def _is_valid_trip(cows, trip):
valid = False
for cow_name in cows:
if cow_name in trip:
valid = True
else:
valid = False
return valid
possibles = []
for partition in possible_combinations:
trips = []
for trip in partition:
total = sum([cows.get(cow) for cow in trip])
if total <= limit and _is_valid_trip(cows.keys(), trip):
trips.append(trip)
possibles.append(trips)
all_possibilities = [possibility for possibility in possibles if possibility != []]
return min(all_possibilities)
我的 TestCase 仍然给出:
AssertionError: Lists differ: [['Callie', 'Maggie']] != [['Jesse', 'Callie'], ['Maybel', 'Maggie']]
First differing element 0:
['Callie', 'Maggie']
['Jesse', 'Callie']
Second list contains 1 additional elements.
First extra element 1:
['Maybel', 'Maggie']
- [['Callie', 'Maggie']]
+ [['Jesse', 'Callie'], ['Maybel', 'Maggie']]
----------------------------------------------------------------------
Ran 5 tests in 0.009s
FAILED (failures=1)
解决方案
这是我从正确答案中得到的最接近的结果。首先,我使用 get_partitions 生成所有可能的分区,然后我将分区过滤到一个名为 possible 的列表中,其中只有限制 <= 10 的行程,并且行程中包含所有奶牛(排除那些只有一个或两个奶牛名称的分区)。
这是正确的想法,除了最后一条语句,根据定义,集合的分区将只包含集合的所有元素一次。问题是您是从行程而不是分区构建列表,没有必要这样做,因为您已经在 possible_combinations 中生成了完整的分区集,您需要做的就是删除那些包含超过权重的行程的分区限制这会给你留下这样的东西:
def brute_force_cow_transport(cows, limit):
## Generate set of partitions
possible_combinations = []
for partition in get_partitions(cows.keys()):
possible_combinations.append(partition)
possible_combinations.sort(key=len)
valid_combinations = possible_combinations[:] ## or list.copy() if using python 3.3+
## Remove invalid partitions
for partition in possible_combinations:
for trip in partition:
total = sum([cows.get(cow) for cow in trip])
if total > limit:
valid_combinations.remove(partition)
break
## Return valid partition of minimum length
return min(valid_combinations, key=len)
在这里,由于我们正在迭代分区,因此我们首先制作分区列表的副本,以便我们可以删除包含超出限制的行程的分区,然后返回最小长度的列表作为解决方案。有一些简单的方法可以提高它的性能,但它们留给读者作为练习。
推荐阅读
- typescript - Typescript/Request-Promise:无法调用类型缺少调用签名的表达式
- c# - C# 泛型 - out 关键字 - '方法的返回类型错误'
- apache - ssl 证书后,第二个虚拟主机域转发到 apache 测试页面
- ajax - Laravel ajax 给出错误 500
- python - 如何并行运行多个命令并获得它们的输出(通过/失败)?
- amazon-web-services - 如何创建代理以查看 AWS Glue 的 Spark UI 上的作业?
- azure-sdk-.net - Azure SDK 4 .NET 是否支持 Azure gov?
- android - Android DSP - AudioTrack 和亚音频信号的问题
- javascript - Fetch() 和 array.push() 后数组为空
- php - MySQL - 如何从 SELECT 查询中获取多个结果