I'm studying Optimization Problems and I got stuck at a homework problem. I have to write a Brute Force algorithm to minimizes the number of spaceship trips. The problem is: aliens created a new type of cow and now they want to transport it back with the minimum number of trips. Each trip has the maximum value of 10 tons.
The exercise provided some things, like this algorithm to get all possible partitions for a list:
# 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]
The input is a dict of cows, like this one: cows = {'Jesse': 6,'Maybel': 3, 'Callie': 2, 'Maggie': 5}, with the key being the name of the cow and the value being the cow's weight in tons.
The output must be a list of lists, where each inner list represents a trip, like this one: [['Jesse', 'Callie'], ['Maybel', 'Maggie']]
My question is: How can I implement this algorithm using get_partitions()? Does DFS is a good way to solve this?
I tried many ways already, but two of them I found at stackoverflow, that seemed to be closer to the answer was:
Got all possible combinations using the get_partitions() function and selected all that obey the
limit = 10
inside a list. Like I saw here: Why is this brute force algorithm producing the incorrect result? but it didn't work because it was returning an empty list.Then I tried Depth First Search, like I saw in here with a few changes: How to find best solution from all brute force combinations? and the lists are not returning the correct answer yet.
This was the closest I get from the correct answer. First I used get_partitions to generate all possible partitions, then I filtered the partitions to a list named possible with only trips with limit <= 10
and if the trips had all cows inside (to exclude those partitions with only one or two cow names).
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)
My TestCase for this still gives:
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)