Python create order from smaller packages
The input is an integer that specifies the amount to be ordered.
There are predefined package sizes that have to be used to create that order.
e.g.
Packs
3 for $5
5 for $9
9 for $16
for an input order 13 the output should be:
2x5 + 1x3
So far I've the following approach
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
while remaining_order > 0:
found = False
for pack_num in package_numbers:
if pack_num <= remaining_order:
required_packages.append(pack_num)
remaining_order -= pack_num
found = True
break
if not found:
break
But this will lead to the wrong result
1x9 + 1x3
remaining: 1
python
This question has an open bounty worth +100
reputation from wasp256 ending in 5 days.
This question has not received enough attention.
|
show 15 more comments
The input is an integer that specifies the amount to be ordered.
There are predefined package sizes that have to be used to create that order.
e.g.
Packs
3 for $5
5 for $9
9 for $16
for an input order 13 the output should be:
2x5 + 1x3
So far I've the following approach
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
while remaining_order > 0:
found = False
for pack_num in package_numbers:
if pack_num <= remaining_order:
required_packages.append(pack_num)
remaining_order -= pack_num
found = True
break
if not found:
break
But this will lead to the wrong result
1x9 + 1x3
remaining: 1
python
This question has an open bounty worth +100
reputation from wasp256 ending in 5 days.
This question has not received enough attention.
1
As an aside, in Python, afor
can have anelse
.
– tripleee
Jan 16 at 7:13
1
Can you specify boundaries? Will it be 3 package sizes max or may there be 20000? Biggest input?
– DonQuiKong
yesterday
1
@BlueSheepToken lowest price I think, so 9. I'd even think that combination of biggest inputs should suffice, prices don't normally favor smaller package_sizes, but op should answer that.
– DonQuiKong
yesterday
1
@BlueSheepToken oh damn, you're right, the prices aren't quite logical. That .. basically reduces the possible input packages to 3 and 5 though in this case.
– DonQuiKong
yesterday
1
Which also means that trivially any input greater than 22 (2*5 + 4*3) can be solved by going mod 15 because necessarily there is either 3*5 or 5*3 in the solution which both is 15. Rest .. lut.
– DonQuiKong
yesterday
|
show 15 more comments
The input is an integer that specifies the amount to be ordered.
There are predefined package sizes that have to be used to create that order.
e.g.
Packs
3 for $5
5 for $9
9 for $16
for an input order 13 the output should be:
2x5 + 1x3
So far I've the following approach
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
while remaining_order > 0:
found = False
for pack_num in package_numbers:
if pack_num <= remaining_order:
required_packages.append(pack_num)
remaining_order -= pack_num
found = True
break
if not found:
break
But this will lead to the wrong result
1x9 + 1x3
remaining: 1
python
The input is an integer that specifies the amount to be ordered.
There are predefined package sizes that have to be used to create that order.
e.g.
Packs
3 for $5
5 for $9
9 for $16
for an input order 13 the output should be:
2x5 + 1x3
So far I've the following approach
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
while remaining_order > 0:
found = False
for pack_num in package_numbers:
if pack_num <= remaining_order:
required_packages.append(pack_num)
remaining_order -= pack_num
found = True
break
if not found:
break
But this will lead to the wrong result
1x9 + 1x3
remaining: 1
python
python
edited Jan 16 at 7:17
wasp256
asked Jan 16 at 6:44
wasp256wasp256
2,11643266
2,11643266
This question has an open bounty worth +100
reputation from wasp256 ending in 5 days.
This question has not received enough attention.
This question has an open bounty worth +100
reputation from wasp256 ending in 5 days.
This question has not received enough attention.
1
As an aside, in Python, afor
can have anelse
.
– tripleee
Jan 16 at 7:13
1
Can you specify boundaries? Will it be 3 package sizes max or may there be 20000? Biggest input?
– DonQuiKong
yesterday
1
@BlueSheepToken lowest price I think, so 9. I'd even think that combination of biggest inputs should suffice, prices don't normally favor smaller package_sizes, but op should answer that.
– DonQuiKong
yesterday
1
@BlueSheepToken oh damn, you're right, the prices aren't quite logical. That .. basically reduces the possible input packages to 3 and 5 though in this case.
– DonQuiKong
yesterday
1
Which also means that trivially any input greater than 22 (2*5 + 4*3) can be solved by going mod 15 because necessarily there is either 3*5 or 5*3 in the solution which both is 15. Rest .. lut.
– DonQuiKong
yesterday
|
show 15 more comments
1
As an aside, in Python, afor
can have anelse
.
– tripleee
Jan 16 at 7:13
1
Can you specify boundaries? Will it be 3 package sizes max or may there be 20000? Biggest input?
– DonQuiKong
yesterday
1
@BlueSheepToken lowest price I think, so 9. I'd even think that combination of biggest inputs should suffice, prices don't normally favor smaller package_sizes, but op should answer that.
– DonQuiKong
yesterday
1
@BlueSheepToken oh damn, you're right, the prices aren't quite logical. That .. basically reduces the possible input packages to 3 and 5 though in this case.
– DonQuiKong
yesterday
1
Which also means that trivially any input greater than 22 (2*5 + 4*3) can be solved by going mod 15 because necessarily there is either 3*5 or 5*3 in the solution which both is 15. Rest .. lut.
– DonQuiKong
yesterday
1
1
As an aside, in Python, a
for
can have an else
.– tripleee
Jan 16 at 7:13
As an aside, in Python, a
for
can have an else
.– tripleee
Jan 16 at 7:13
1
1
Can you specify boundaries? Will it be 3 package sizes max or may there be 20000? Biggest input?
– DonQuiKong
yesterday
Can you specify boundaries? Will it be 3 package sizes max or may there be 20000? Biggest input?
– DonQuiKong
yesterday
1
1
@BlueSheepToken lowest price I think, so 9. I'd even think that combination of biggest inputs should suffice, prices don't normally favor smaller package_sizes, but op should answer that.
– DonQuiKong
yesterday
@BlueSheepToken lowest price I think, so 9. I'd even think that combination of biggest inputs should suffice, prices don't normally favor smaller package_sizes, but op should answer that.
– DonQuiKong
yesterday
1
1
@BlueSheepToken oh damn, you're right, the prices aren't quite logical. That .. basically reduces the possible input packages to 3 and 5 though in this case.
– DonQuiKong
yesterday
@BlueSheepToken oh damn, you're right, the prices aren't quite logical. That .. basically reduces the possible input packages to 3 and 5 though in this case.
– DonQuiKong
yesterday
1
1
Which also means that trivially any input greater than 22 (2*5 + 4*3) can be solved by going mod 15 because necessarily there is either 3*5 or 5*3 in the solution which both is 15. Rest .. lut.
– DonQuiKong
yesterday
Which also means that trivially any input greater than 22 (2*5 + 4*3) can be solved by going mod 15 because necessarily there is either 3*5 or 5*3 in the solution which both is 15. Rest .. lut.
– DonQuiKong
yesterday
|
show 15 more comments
5 Answers
5
active
oldest
votes
So, you need to fill the order with the packages such that the total price is maximal? This is known as Knapsack problem. In that Wikipedia article you'll find several solutions written in Python.
To be more precise, you need a solution for the unbounded knapsack problem, in contrast to popular 0/1 knapsack problem (where each item can be packed only once). Here is working code from Rosetta:
from itertools import product
NAME, SIZE, VALUE = range(3)
items = (
# NAME, SIZE, VALUE
('A', 3, 5),
('B', 5, 9),
('C', 9, 16))
capacity = 13
def knapsack_unbounded_enumeration(items, C):
# find max of any one item
max1 = [int(C / item[SIZE]) for item in items]
itemsizes = [item[SIZE] for item in items]
itemvalues = [item[VALUE] for item in items]
# def totvalue(itemscount, =itemsizes, itemvalues=itemvalues, C=C):
def totvalue(itemscount):
# nonlocal itemsizes, itemvalues, C
totsize = sum(n * size for n, size in zip(itemscount, itemsizes))
totval = sum(n * val for n, val in zip(itemscount, itemvalues))
return (totval, -totsize) if totsize <= C else (-1, 0)
# Try all combinations of bounty items from 0 up to max1
bagged = max(product(*[range(n + 1) for n in max1]), key=totvalue)
numbagged = sum(bagged)
value, size = totvalue(bagged)
size = -size
# convert to (iten, count) pairs) in name order
bagged = ['%dx%d' % (n, items[i][SIZE]) for i, n in enumerate(bagged) if n]
return value, size, numbagged, bagged
if __name__ == '__main__':
value, size, numbagged, bagged = knapsack_unbounded_enumeration(items, capacity)
print(value)
print(bagged)
Output is:
23
['1x3', '2x5']
Keep in mind that this is a NP-hard problem, so it will blow as you enter some large values :)
1
Am... link-only answers will be deleted in the low quality posts review page.
– U9-Forward
yesterday
1
@U9-Forward there's a meta discussion around somewhere, this is, barely, but still, an answer because it can be reproduced even if the link goes dead -> knapsack problem, wikipedia, done.
– DonQuiKong
yesterday
add a comment |
You can use itertools.product
:
import itertools
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
a=min([x for i in range(1,remaining_order+1//min(package_numbers)) for x in itertools.product(package_numbers,repeat=i)],key=lambda x: abs(sum(x)-remaining_order))
remaining_order-=sum(a)
print(a)
print(remaining_order)
Output:
(5, 5, 3)
0
This simply does the below steps:
Get value closest to
13
, in the list with all the product values.Then simply make it modify the number of
remaining_order
.
2
I entered 130000 as remaining_order and had to kill it with fire ;), I then entered 130 and it's still not finished
– DonQuiKong
yesterday
@DonQuiKong Well... any code doing that number would have to be killed and you would actually have your window being not responding, so restart shell...
– U9-Forward
yesterday
1
130 -> MemoryError
– DonQuiKong
yesterday
@DonQuiKong That's still kinda big... can ya think of other examples, anyway, bye, i have to go.
– U9-Forward
yesterday
1
Try integer factorisation withitertools
next :)
– Dima Tisnek
yesterday
add a comment |
For you problem, I tried two implementations depending on what you want, in both of the solutions I supposed you absolutely needed your remaining to be at 0. Otherwise the algorithm will return you -1
. If you need them, tell me I can adapt my algorithm.
As the algorithm is implemented via dynamic programming, it handles good inputs, at least more than 130 packages !
In the first solution, I admitted we fill with the biggest package each time.
I n the second solution, I try to minimize the price, but the number of packages should always be 0.
remaining_order = 13
package_numbers = sorted([9,5,3], reverse=True) # To make sure the biggest package is the first element
prices = {9: 16, 5: 9, 3: 5}
required_packages =
# First solution, using the biggest package each time, and making the total order remaining at 0 each time
ans = [ for _ in range(remaining_order + 1)]
ans[0] = [0, 0, 0]
for i in range(1, remaining_order + 1):
for index, package_number in enumerate(package_numbers):
if i-package_number > -1:
tmp = ans[i-package_number]
if tmp != -1:
ans[i] = [tmp[x] if x != index else tmp[x] + 1 for x in range(len(tmp))]
break
else: # Using for else instead of a boolean value `found`
ans[i] = -1 # -1 is the not found combinations
print(ans[13]) # [0, 2, 1]
print(ans[9]) # [1, 0, 0]
# Second solution, minimizing the price with order at 0
def price(x):
return 16*x[0]+9*x[1]+5*x[2]
ans = [ for _ in range(remaining_order + 1)]
ans[0] = ([0, 0, 0],0) # combination + price
for i in range(1, remaining_order + 1):
# The not found packages will be (-1, float('inf'))
minimal_price = float('inf')
minimal_combinations = -1
for index, package_number in enumerate(package_numbers):
if i-package_number > -1:
tmp = ans[i-package_number]
if tmp != (-1, float('inf')):
tmp_price = price(tmp[0]) + prices[package_number]
if tmp_price < minimal_price:
minimal_price = tmp_price
minimal_combinations = [tmp[0][x] if x != index else tmp[0][x] + 1 for x in range(len(tmp[0]))]
ans[i] = (minimal_combinations, minimal_price)
print(ans[13]) # ([0, 2, 1], 23)
print(ans[9]) # ([0, 0, 3], 15) Because the price of three packages is lower than the price of a package of 9
Mmmhh... this is right, I will remove the side note for the moment, will put it back later if I find the mathematical proof :p
– BlueSheepToken
yesterday
It should be 9*(5*3-1) + 5*(3*9-1) + 3*(9*5-1) because for example for 5 and 3 5*3 would be 15, but two times 5 and two times 3 is 16 which is a possible number but can't be solved with mod 15.
– DonQuiKong
yesterday
However, if any package is in there for self_value*product_of_rest, the mod takes it out. So any combination of a single package bigger than each package times product_of_all_other_package_values-1 can be ignored.
– DonQuiKong
yesterday
add a comment |
In case you need a solution for a small number of possible
package_numbers
but a possibly very big
remaining_order,
in which case all the other solutions would fail, you can use this to reduce remaining_order:
import numpy as np
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
sub_max=np.sum([(np.product(package_numbers)/i-1)*i for i in package_numbers])
while remaining_order > sub_max:
remaining_order -= np.product(package_numbers)
required_packages.append([max(package_numbers)]*np.product(package_numbers)/max(package_numbers))
Because if any package is in required_packages more often than (np.product(package_numbers)/i-1)*i it's sum is equal to np.product(package_numbers). In case the package max(package_numbers) isn't the one with the samllest price per unit, take the one with the smallest price per unit instead.
Example:
remaining_order = 100
package_numbers = [5,3]
Any part of remaining_order bigger than 5*2 plus 3*4 = 22 can be sorted out by adding 5 three times to the solution and taking remaining_order - 5*3.
So remaining order that actually needs to be calculated is 10. Which can then be solved to beeing 2 times 5. The rest is filled with 6 times 15 which is 18 times 5.
In case the number of possible package_numbers is bigger than just a handful, I recommend building a lookup table (with one of the others answers' code) for all numbers below sub_max which will make this immensely fast for any input.
add a comment |
Since no declaration about the object function is found, I assume your goal is to maximize the package value within the pack's capability.
Explanation: time complexity is fixed. Optimal solution may not be filling the highest valued item as many as possible, you have to search all possible combinations. However, you can reuse the possible optimal solutions you have searched to save space. For example, [5,5,3]
is derived from adding 3
to a previous [5,5]
try so the intermediate result can be "cached". You may either use an array or you may use a set to store possible solutions. The code below runs the same performance as the rosetta code but I think it's clearer.
To further optimize, use a priority set for opts
.
costs = [3,5,9]
value = [5,9,16]
volume = 130
# solutions
opts = set()
opts.add(tuple([0]))
# calc total value
cost_val = dict(zip(costs, value))
def total_value(opt):
return sum([cost_val.get(cost,0) for cost in opt])
def possible_solutions():
solutions = set()
for opt in opts:
for cost in costs:
if cost + sum(opt) > volume:
continue
cnt = (volume - sum(opt)) // cost
for _ in range(1, cnt + 1):
sol = tuple(list(opt) + [cost] * _)
solutions.add(sol)
return solutions
def optimize_max_return(opts):
if not opts:
return tuple()
cur = list(opts)[0]
for sol in opts:
if total_value(sol) > total_value(cur):
cur = sol
return cur
while sum(optimize_max_return(opts)) <= volume - min(costs):
opts = opts.union(possible_solutions())
print(optimize_max_return(opts))
If your requirement is "just fill the pack" it'll be even simpler using the volume for each item instead.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54211693%2fpython-create-order-from-smaller-packages%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
So, you need to fill the order with the packages such that the total price is maximal? This is known as Knapsack problem. In that Wikipedia article you'll find several solutions written in Python.
To be more precise, you need a solution for the unbounded knapsack problem, in contrast to popular 0/1 knapsack problem (where each item can be packed only once). Here is working code from Rosetta:
from itertools import product
NAME, SIZE, VALUE = range(3)
items = (
# NAME, SIZE, VALUE
('A', 3, 5),
('B', 5, 9),
('C', 9, 16))
capacity = 13
def knapsack_unbounded_enumeration(items, C):
# find max of any one item
max1 = [int(C / item[SIZE]) for item in items]
itemsizes = [item[SIZE] for item in items]
itemvalues = [item[VALUE] for item in items]
# def totvalue(itemscount, =itemsizes, itemvalues=itemvalues, C=C):
def totvalue(itemscount):
# nonlocal itemsizes, itemvalues, C
totsize = sum(n * size for n, size in zip(itemscount, itemsizes))
totval = sum(n * val for n, val in zip(itemscount, itemvalues))
return (totval, -totsize) if totsize <= C else (-1, 0)
# Try all combinations of bounty items from 0 up to max1
bagged = max(product(*[range(n + 1) for n in max1]), key=totvalue)
numbagged = sum(bagged)
value, size = totvalue(bagged)
size = -size
# convert to (iten, count) pairs) in name order
bagged = ['%dx%d' % (n, items[i][SIZE]) for i, n in enumerate(bagged) if n]
return value, size, numbagged, bagged
if __name__ == '__main__':
value, size, numbagged, bagged = knapsack_unbounded_enumeration(items, capacity)
print(value)
print(bagged)
Output is:
23
['1x3', '2x5']
Keep in mind that this is a NP-hard problem, so it will blow as you enter some large values :)
1
Am... link-only answers will be deleted in the low quality posts review page.
– U9-Forward
yesterday
1
@U9-Forward there's a meta discussion around somewhere, this is, barely, but still, an answer because it can be reproduced even if the link goes dead -> knapsack problem, wikipedia, done.
– DonQuiKong
yesterday
add a comment |
So, you need to fill the order with the packages such that the total price is maximal? This is known as Knapsack problem. In that Wikipedia article you'll find several solutions written in Python.
To be more precise, you need a solution for the unbounded knapsack problem, in contrast to popular 0/1 knapsack problem (where each item can be packed only once). Here is working code from Rosetta:
from itertools import product
NAME, SIZE, VALUE = range(3)
items = (
# NAME, SIZE, VALUE
('A', 3, 5),
('B', 5, 9),
('C', 9, 16))
capacity = 13
def knapsack_unbounded_enumeration(items, C):
# find max of any one item
max1 = [int(C / item[SIZE]) for item in items]
itemsizes = [item[SIZE] for item in items]
itemvalues = [item[VALUE] for item in items]
# def totvalue(itemscount, =itemsizes, itemvalues=itemvalues, C=C):
def totvalue(itemscount):
# nonlocal itemsizes, itemvalues, C
totsize = sum(n * size for n, size in zip(itemscount, itemsizes))
totval = sum(n * val for n, val in zip(itemscount, itemvalues))
return (totval, -totsize) if totsize <= C else (-1, 0)
# Try all combinations of bounty items from 0 up to max1
bagged = max(product(*[range(n + 1) for n in max1]), key=totvalue)
numbagged = sum(bagged)
value, size = totvalue(bagged)
size = -size
# convert to (iten, count) pairs) in name order
bagged = ['%dx%d' % (n, items[i][SIZE]) for i, n in enumerate(bagged) if n]
return value, size, numbagged, bagged
if __name__ == '__main__':
value, size, numbagged, bagged = knapsack_unbounded_enumeration(items, capacity)
print(value)
print(bagged)
Output is:
23
['1x3', '2x5']
Keep in mind that this is a NP-hard problem, so it will blow as you enter some large values :)
1
Am... link-only answers will be deleted in the low quality posts review page.
– U9-Forward
yesterday
1
@U9-Forward there's a meta discussion around somewhere, this is, barely, but still, an answer because it can be reproduced even if the link goes dead -> knapsack problem, wikipedia, done.
– DonQuiKong
yesterday
add a comment |
So, you need to fill the order with the packages such that the total price is maximal? This is known as Knapsack problem. In that Wikipedia article you'll find several solutions written in Python.
To be more precise, you need a solution for the unbounded knapsack problem, in contrast to popular 0/1 knapsack problem (where each item can be packed only once). Here is working code from Rosetta:
from itertools import product
NAME, SIZE, VALUE = range(3)
items = (
# NAME, SIZE, VALUE
('A', 3, 5),
('B', 5, 9),
('C', 9, 16))
capacity = 13
def knapsack_unbounded_enumeration(items, C):
# find max of any one item
max1 = [int(C / item[SIZE]) for item in items]
itemsizes = [item[SIZE] for item in items]
itemvalues = [item[VALUE] for item in items]
# def totvalue(itemscount, =itemsizes, itemvalues=itemvalues, C=C):
def totvalue(itemscount):
# nonlocal itemsizes, itemvalues, C
totsize = sum(n * size for n, size in zip(itemscount, itemsizes))
totval = sum(n * val for n, val in zip(itemscount, itemvalues))
return (totval, -totsize) if totsize <= C else (-1, 0)
# Try all combinations of bounty items from 0 up to max1
bagged = max(product(*[range(n + 1) for n in max1]), key=totvalue)
numbagged = sum(bagged)
value, size = totvalue(bagged)
size = -size
# convert to (iten, count) pairs) in name order
bagged = ['%dx%d' % (n, items[i][SIZE]) for i, n in enumerate(bagged) if n]
return value, size, numbagged, bagged
if __name__ == '__main__':
value, size, numbagged, bagged = knapsack_unbounded_enumeration(items, capacity)
print(value)
print(bagged)
Output is:
23
['1x3', '2x5']
Keep in mind that this is a NP-hard problem, so it will blow as you enter some large values :)
So, you need to fill the order with the packages such that the total price is maximal? This is known as Knapsack problem. In that Wikipedia article you'll find several solutions written in Python.
To be more precise, you need a solution for the unbounded knapsack problem, in contrast to popular 0/1 knapsack problem (where each item can be packed only once). Here is working code from Rosetta:
from itertools import product
NAME, SIZE, VALUE = range(3)
items = (
# NAME, SIZE, VALUE
('A', 3, 5),
('B', 5, 9),
('C', 9, 16))
capacity = 13
def knapsack_unbounded_enumeration(items, C):
# find max of any one item
max1 = [int(C / item[SIZE]) for item in items]
itemsizes = [item[SIZE] for item in items]
itemvalues = [item[VALUE] for item in items]
# def totvalue(itemscount, =itemsizes, itemvalues=itemvalues, C=C):
def totvalue(itemscount):
# nonlocal itemsizes, itemvalues, C
totsize = sum(n * size for n, size in zip(itemscount, itemsizes))
totval = sum(n * val for n, val in zip(itemscount, itemvalues))
return (totval, -totsize) if totsize <= C else (-1, 0)
# Try all combinations of bounty items from 0 up to max1
bagged = max(product(*[range(n + 1) for n in max1]), key=totvalue)
numbagged = sum(bagged)
value, size = totvalue(bagged)
size = -size
# convert to (iten, count) pairs) in name order
bagged = ['%dx%d' % (n, items[i][SIZE]) for i, n in enumerate(bagged) if n]
return value, size, numbagged, bagged
if __name__ == '__main__':
value, size, numbagged, bagged = knapsack_unbounded_enumeration(items, capacity)
print(value)
print(bagged)
Output is:
23
['1x3', '2x5']
Keep in mind that this is a NP-hard problem, so it will blow as you enter some large values :)
edited yesterday
answered yesterday
Dmytro PrylipkoDmytro Prylipko
890618
890618
1
Am... link-only answers will be deleted in the low quality posts review page.
– U9-Forward
yesterday
1
@U9-Forward there's a meta discussion around somewhere, this is, barely, but still, an answer because it can be reproduced even if the link goes dead -> knapsack problem, wikipedia, done.
– DonQuiKong
yesterday
add a comment |
1
Am... link-only answers will be deleted in the low quality posts review page.
– U9-Forward
yesterday
1
@U9-Forward there's a meta discussion around somewhere, this is, barely, but still, an answer because it can be reproduced even if the link goes dead -> knapsack problem, wikipedia, done.
– DonQuiKong
yesterday
1
1
Am... link-only answers will be deleted in the low quality posts review page.
– U9-Forward
yesterday
Am... link-only answers will be deleted in the low quality posts review page.
– U9-Forward
yesterday
1
1
@U9-Forward there's a meta discussion around somewhere, this is, barely, but still, an answer because it can be reproduced even if the link goes dead -> knapsack problem, wikipedia, done.
– DonQuiKong
yesterday
@U9-Forward there's a meta discussion around somewhere, this is, barely, but still, an answer because it can be reproduced even if the link goes dead -> knapsack problem, wikipedia, done.
– DonQuiKong
yesterday
add a comment |
You can use itertools.product
:
import itertools
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
a=min([x for i in range(1,remaining_order+1//min(package_numbers)) for x in itertools.product(package_numbers,repeat=i)],key=lambda x: abs(sum(x)-remaining_order))
remaining_order-=sum(a)
print(a)
print(remaining_order)
Output:
(5, 5, 3)
0
This simply does the below steps:
Get value closest to
13
, in the list with all the product values.Then simply make it modify the number of
remaining_order
.
2
I entered 130000 as remaining_order and had to kill it with fire ;), I then entered 130 and it's still not finished
– DonQuiKong
yesterday
@DonQuiKong Well... any code doing that number would have to be killed and you would actually have your window being not responding, so restart shell...
– U9-Forward
yesterday
1
130 -> MemoryError
– DonQuiKong
yesterday
@DonQuiKong That's still kinda big... can ya think of other examples, anyway, bye, i have to go.
– U9-Forward
yesterday
1
Try integer factorisation withitertools
next :)
– Dima Tisnek
yesterday
add a comment |
You can use itertools.product
:
import itertools
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
a=min([x for i in range(1,remaining_order+1//min(package_numbers)) for x in itertools.product(package_numbers,repeat=i)],key=lambda x: abs(sum(x)-remaining_order))
remaining_order-=sum(a)
print(a)
print(remaining_order)
Output:
(5, 5, 3)
0
This simply does the below steps:
Get value closest to
13
, in the list with all the product values.Then simply make it modify the number of
remaining_order
.
2
I entered 130000 as remaining_order and had to kill it with fire ;), I then entered 130 and it's still not finished
– DonQuiKong
yesterday
@DonQuiKong Well... any code doing that number would have to be killed and you would actually have your window being not responding, so restart shell...
– U9-Forward
yesterday
1
130 -> MemoryError
– DonQuiKong
yesterday
@DonQuiKong That's still kinda big... can ya think of other examples, anyway, bye, i have to go.
– U9-Forward
yesterday
1
Try integer factorisation withitertools
next :)
– Dima Tisnek
yesterday
add a comment |
You can use itertools.product
:
import itertools
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
a=min([x for i in range(1,remaining_order+1//min(package_numbers)) for x in itertools.product(package_numbers,repeat=i)],key=lambda x: abs(sum(x)-remaining_order))
remaining_order-=sum(a)
print(a)
print(remaining_order)
Output:
(5, 5, 3)
0
This simply does the below steps:
Get value closest to
13
, in the list with all the product values.Then simply make it modify the number of
remaining_order
.
You can use itertools.product
:
import itertools
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
a=min([x for i in range(1,remaining_order+1//min(package_numbers)) for x in itertools.product(package_numbers,repeat=i)],key=lambda x: abs(sum(x)-remaining_order))
remaining_order-=sum(a)
print(a)
print(remaining_order)
Output:
(5, 5, 3)
0
This simply does the below steps:
Get value closest to
13
, in the list with all the product values.Then simply make it modify the number of
remaining_order
.
edited yesterday
answered yesterday
U9-ForwardU9-Forward
14.2k21337
14.2k21337
2
I entered 130000 as remaining_order and had to kill it with fire ;), I then entered 130 and it's still not finished
– DonQuiKong
yesterday
@DonQuiKong Well... any code doing that number would have to be killed and you would actually have your window being not responding, so restart shell...
– U9-Forward
yesterday
1
130 -> MemoryError
– DonQuiKong
yesterday
@DonQuiKong That's still kinda big... can ya think of other examples, anyway, bye, i have to go.
– U9-Forward
yesterday
1
Try integer factorisation withitertools
next :)
– Dima Tisnek
yesterday
add a comment |
2
I entered 130000 as remaining_order and had to kill it with fire ;), I then entered 130 and it's still not finished
– DonQuiKong
yesterday
@DonQuiKong Well... any code doing that number would have to be killed and you would actually have your window being not responding, so restart shell...
– U9-Forward
yesterday
1
130 -> MemoryError
– DonQuiKong
yesterday
@DonQuiKong That's still kinda big... can ya think of other examples, anyway, bye, i have to go.
– U9-Forward
yesterday
1
Try integer factorisation withitertools
next :)
– Dima Tisnek
yesterday
2
2
I entered 130000 as remaining_order and had to kill it with fire ;), I then entered 130 and it's still not finished
– DonQuiKong
yesterday
I entered 130000 as remaining_order and had to kill it with fire ;), I then entered 130 and it's still not finished
– DonQuiKong
yesterday
@DonQuiKong Well... any code doing that number would have to be killed and you would actually have your window being not responding, so restart shell...
– U9-Forward
yesterday
@DonQuiKong Well... any code doing that number would have to be killed and you would actually have your window being not responding, so restart shell...
– U9-Forward
yesterday
1
1
130 -> MemoryError
– DonQuiKong
yesterday
130 -> MemoryError
– DonQuiKong
yesterday
@DonQuiKong That's still kinda big... can ya think of other examples, anyway, bye, i have to go.
– U9-Forward
yesterday
@DonQuiKong That's still kinda big... can ya think of other examples, anyway, bye, i have to go.
– U9-Forward
yesterday
1
1
Try integer factorisation with
itertools
next :)– Dima Tisnek
yesterday
Try integer factorisation with
itertools
next :)– Dima Tisnek
yesterday
add a comment |
For you problem, I tried two implementations depending on what you want, in both of the solutions I supposed you absolutely needed your remaining to be at 0. Otherwise the algorithm will return you -1
. If you need them, tell me I can adapt my algorithm.
As the algorithm is implemented via dynamic programming, it handles good inputs, at least more than 130 packages !
In the first solution, I admitted we fill with the biggest package each time.
I n the second solution, I try to minimize the price, but the number of packages should always be 0.
remaining_order = 13
package_numbers = sorted([9,5,3], reverse=True) # To make sure the biggest package is the first element
prices = {9: 16, 5: 9, 3: 5}
required_packages =
# First solution, using the biggest package each time, and making the total order remaining at 0 each time
ans = [ for _ in range(remaining_order + 1)]
ans[0] = [0, 0, 0]
for i in range(1, remaining_order + 1):
for index, package_number in enumerate(package_numbers):
if i-package_number > -1:
tmp = ans[i-package_number]
if tmp != -1:
ans[i] = [tmp[x] if x != index else tmp[x] + 1 for x in range(len(tmp))]
break
else: # Using for else instead of a boolean value `found`
ans[i] = -1 # -1 is the not found combinations
print(ans[13]) # [0, 2, 1]
print(ans[9]) # [1, 0, 0]
# Second solution, minimizing the price with order at 0
def price(x):
return 16*x[0]+9*x[1]+5*x[2]
ans = [ for _ in range(remaining_order + 1)]
ans[0] = ([0, 0, 0],0) # combination + price
for i in range(1, remaining_order + 1):
# The not found packages will be (-1, float('inf'))
minimal_price = float('inf')
minimal_combinations = -1
for index, package_number in enumerate(package_numbers):
if i-package_number > -1:
tmp = ans[i-package_number]
if tmp != (-1, float('inf')):
tmp_price = price(tmp[0]) + prices[package_number]
if tmp_price < minimal_price:
minimal_price = tmp_price
minimal_combinations = [tmp[0][x] if x != index else tmp[0][x] + 1 for x in range(len(tmp[0]))]
ans[i] = (minimal_combinations, minimal_price)
print(ans[13]) # ([0, 2, 1], 23)
print(ans[9]) # ([0, 0, 3], 15) Because the price of three packages is lower than the price of a package of 9
Mmmhh... this is right, I will remove the side note for the moment, will put it back later if I find the mathematical proof :p
– BlueSheepToken
yesterday
It should be 9*(5*3-1) + 5*(3*9-1) + 3*(9*5-1) because for example for 5 and 3 5*3 would be 15, but two times 5 and two times 3 is 16 which is a possible number but can't be solved with mod 15.
– DonQuiKong
yesterday
However, if any package is in there for self_value*product_of_rest, the mod takes it out. So any combination of a single package bigger than each package times product_of_all_other_package_values-1 can be ignored.
– DonQuiKong
yesterday
add a comment |
For you problem, I tried two implementations depending on what you want, in both of the solutions I supposed you absolutely needed your remaining to be at 0. Otherwise the algorithm will return you -1
. If you need them, tell me I can adapt my algorithm.
As the algorithm is implemented via dynamic programming, it handles good inputs, at least more than 130 packages !
In the first solution, I admitted we fill with the biggest package each time.
I n the second solution, I try to minimize the price, but the number of packages should always be 0.
remaining_order = 13
package_numbers = sorted([9,5,3], reverse=True) # To make sure the biggest package is the first element
prices = {9: 16, 5: 9, 3: 5}
required_packages =
# First solution, using the biggest package each time, and making the total order remaining at 0 each time
ans = [ for _ in range(remaining_order + 1)]
ans[0] = [0, 0, 0]
for i in range(1, remaining_order + 1):
for index, package_number in enumerate(package_numbers):
if i-package_number > -1:
tmp = ans[i-package_number]
if tmp != -1:
ans[i] = [tmp[x] if x != index else tmp[x] + 1 for x in range(len(tmp))]
break
else: # Using for else instead of a boolean value `found`
ans[i] = -1 # -1 is the not found combinations
print(ans[13]) # [0, 2, 1]
print(ans[9]) # [1, 0, 0]
# Second solution, minimizing the price with order at 0
def price(x):
return 16*x[0]+9*x[1]+5*x[2]
ans = [ for _ in range(remaining_order + 1)]
ans[0] = ([0, 0, 0],0) # combination + price
for i in range(1, remaining_order + 1):
# The not found packages will be (-1, float('inf'))
minimal_price = float('inf')
minimal_combinations = -1
for index, package_number in enumerate(package_numbers):
if i-package_number > -1:
tmp = ans[i-package_number]
if tmp != (-1, float('inf')):
tmp_price = price(tmp[0]) + prices[package_number]
if tmp_price < minimal_price:
minimal_price = tmp_price
minimal_combinations = [tmp[0][x] if x != index else tmp[0][x] + 1 for x in range(len(tmp[0]))]
ans[i] = (minimal_combinations, minimal_price)
print(ans[13]) # ([0, 2, 1], 23)
print(ans[9]) # ([0, 0, 3], 15) Because the price of three packages is lower than the price of a package of 9
Mmmhh... this is right, I will remove the side note for the moment, will put it back later if I find the mathematical proof :p
– BlueSheepToken
yesterday
It should be 9*(5*3-1) + 5*(3*9-1) + 3*(9*5-1) because for example for 5 and 3 5*3 would be 15, but two times 5 and two times 3 is 16 which is a possible number but can't be solved with mod 15.
– DonQuiKong
yesterday
However, if any package is in there for self_value*product_of_rest, the mod takes it out. So any combination of a single package bigger than each package times product_of_all_other_package_values-1 can be ignored.
– DonQuiKong
yesterday
add a comment |
For you problem, I tried two implementations depending on what you want, in both of the solutions I supposed you absolutely needed your remaining to be at 0. Otherwise the algorithm will return you -1
. If you need them, tell me I can adapt my algorithm.
As the algorithm is implemented via dynamic programming, it handles good inputs, at least more than 130 packages !
In the first solution, I admitted we fill with the biggest package each time.
I n the second solution, I try to minimize the price, but the number of packages should always be 0.
remaining_order = 13
package_numbers = sorted([9,5,3], reverse=True) # To make sure the biggest package is the first element
prices = {9: 16, 5: 9, 3: 5}
required_packages =
# First solution, using the biggest package each time, and making the total order remaining at 0 each time
ans = [ for _ in range(remaining_order + 1)]
ans[0] = [0, 0, 0]
for i in range(1, remaining_order + 1):
for index, package_number in enumerate(package_numbers):
if i-package_number > -1:
tmp = ans[i-package_number]
if tmp != -1:
ans[i] = [tmp[x] if x != index else tmp[x] + 1 for x in range(len(tmp))]
break
else: # Using for else instead of a boolean value `found`
ans[i] = -1 # -1 is the not found combinations
print(ans[13]) # [0, 2, 1]
print(ans[9]) # [1, 0, 0]
# Second solution, minimizing the price with order at 0
def price(x):
return 16*x[0]+9*x[1]+5*x[2]
ans = [ for _ in range(remaining_order + 1)]
ans[0] = ([0, 0, 0],0) # combination + price
for i in range(1, remaining_order + 1):
# The not found packages will be (-1, float('inf'))
minimal_price = float('inf')
minimal_combinations = -1
for index, package_number in enumerate(package_numbers):
if i-package_number > -1:
tmp = ans[i-package_number]
if tmp != (-1, float('inf')):
tmp_price = price(tmp[0]) + prices[package_number]
if tmp_price < minimal_price:
minimal_price = tmp_price
minimal_combinations = [tmp[0][x] if x != index else tmp[0][x] + 1 for x in range(len(tmp[0]))]
ans[i] = (minimal_combinations, minimal_price)
print(ans[13]) # ([0, 2, 1], 23)
print(ans[9]) # ([0, 0, 3], 15) Because the price of three packages is lower than the price of a package of 9
For you problem, I tried two implementations depending on what you want, in both of the solutions I supposed you absolutely needed your remaining to be at 0. Otherwise the algorithm will return you -1
. If you need them, tell me I can adapt my algorithm.
As the algorithm is implemented via dynamic programming, it handles good inputs, at least more than 130 packages !
In the first solution, I admitted we fill with the biggest package each time.
I n the second solution, I try to minimize the price, but the number of packages should always be 0.
remaining_order = 13
package_numbers = sorted([9,5,3], reverse=True) # To make sure the biggest package is the first element
prices = {9: 16, 5: 9, 3: 5}
required_packages =
# First solution, using the biggest package each time, and making the total order remaining at 0 each time
ans = [ for _ in range(remaining_order + 1)]
ans[0] = [0, 0, 0]
for i in range(1, remaining_order + 1):
for index, package_number in enumerate(package_numbers):
if i-package_number > -1:
tmp = ans[i-package_number]
if tmp != -1:
ans[i] = [tmp[x] if x != index else tmp[x] + 1 for x in range(len(tmp))]
break
else: # Using for else instead of a boolean value `found`
ans[i] = -1 # -1 is the not found combinations
print(ans[13]) # [0, 2, 1]
print(ans[9]) # [1, 0, 0]
# Second solution, minimizing the price with order at 0
def price(x):
return 16*x[0]+9*x[1]+5*x[2]
ans = [ for _ in range(remaining_order + 1)]
ans[0] = ([0, 0, 0],0) # combination + price
for i in range(1, remaining_order + 1):
# The not found packages will be (-1, float('inf'))
minimal_price = float('inf')
minimal_combinations = -1
for index, package_number in enumerate(package_numbers):
if i-package_number > -1:
tmp = ans[i-package_number]
if tmp != (-1, float('inf')):
tmp_price = price(tmp[0]) + prices[package_number]
if tmp_price < minimal_price:
minimal_price = tmp_price
minimal_combinations = [tmp[0][x] if x != index else tmp[0][x] + 1 for x in range(len(tmp[0]))]
ans[i] = (minimal_combinations, minimal_price)
print(ans[13]) # ([0, 2, 1], 23)
print(ans[9]) # ([0, 0, 3], 15) Because the price of three packages is lower than the price of a package of 9
edited yesterday
answered yesterday
BlueSheepTokenBlueSheepToken
1,066315
1,066315
Mmmhh... this is right, I will remove the side note for the moment, will put it back later if I find the mathematical proof :p
– BlueSheepToken
yesterday
It should be 9*(5*3-1) + 5*(3*9-1) + 3*(9*5-1) because for example for 5 and 3 5*3 would be 15, but two times 5 and two times 3 is 16 which is a possible number but can't be solved with mod 15.
– DonQuiKong
yesterday
However, if any package is in there for self_value*product_of_rest, the mod takes it out. So any combination of a single package bigger than each package times product_of_all_other_package_values-1 can be ignored.
– DonQuiKong
yesterday
add a comment |
Mmmhh... this is right, I will remove the side note for the moment, will put it back later if I find the mathematical proof :p
– BlueSheepToken
yesterday
It should be 9*(5*3-1) + 5*(3*9-1) + 3*(9*5-1) because for example for 5 and 3 5*3 would be 15, but two times 5 and two times 3 is 16 which is a possible number but can't be solved with mod 15.
– DonQuiKong
yesterday
However, if any package is in there for self_value*product_of_rest, the mod takes it out. So any combination of a single package bigger than each package times product_of_all_other_package_values-1 can be ignored.
– DonQuiKong
yesterday
Mmmhh... this is right, I will remove the side note for the moment, will put it back later if I find the mathematical proof :p
– BlueSheepToken
yesterday
Mmmhh... this is right, I will remove the side note for the moment, will put it back later if I find the mathematical proof :p
– BlueSheepToken
yesterday
It should be 9*(5*3-1) + 5*(3*9-1) + 3*(9*5-1) because for example for 5 and 3 5*3 would be 15, but two times 5 and two times 3 is 16 which is a possible number but can't be solved with mod 15.
– DonQuiKong
yesterday
It should be 9*(5*3-1) + 5*(3*9-1) + 3*(9*5-1) because for example for 5 and 3 5*3 would be 15, but two times 5 and two times 3 is 16 which is a possible number but can't be solved with mod 15.
– DonQuiKong
yesterday
However, if any package is in there for self_value*product_of_rest, the mod takes it out. So any combination of a single package bigger than each package times product_of_all_other_package_values-1 can be ignored.
– DonQuiKong
yesterday
However, if any package is in there for self_value*product_of_rest, the mod takes it out. So any combination of a single package bigger than each package times product_of_all_other_package_values-1 can be ignored.
– DonQuiKong
yesterday
add a comment |
In case you need a solution for a small number of possible
package_numbers
but a possibly very big
remaining_order,
in which case all the other solutions would fail, you can use this to reduce remaining_order:
import numpy as np
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
sub_max=np.sum([(np.product(package_numbers)/i-1)*i for i in package_numbers])
while remaining_order > sub_max:
remaining_order -= np.product(package_numbers)
required_packages.append([max(package_numbers)]*np.product(package_numbers)/max(package_numbers))
Because if any package is in required_packages more often than (np.product(package_numbers)/i-1)*i it's sum is equal to np.product(package_numbers). In case the package max(package_numbers) isn't the one with the samllest price per unit, take the one with the smallest price per unit instead.
Example:
remaining_order = 100
package_numbers = [5,3]
Any part of remaining_order bigger than 5*2 plus 3*4 = 22 can be sorted out by adding 5 three times to the solution and taking remaining_order - 5*3.
So remaining order that actually needs to be calculated is 10. Which can then be solved to beeing 2 times 5. The rest is filled with 6 times 15 which is 18 times 5.
In case the number of possible package_numbers is bigger than just a handful, I recommend building a lookup table (with one of the others answers' code) for all numbers below sub_max which will make this immensely fast for any input.
add a comment |
In case you need a solution for a small number of possible
package_numbers
but a possibly very big
remaining_order,
in which case all the other solutions would fail, you can use this to reduce remaining_order:
import numpy as np
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
sub_max=np.sum([(np.product(package_numbers)/i-1)*i for i in package_numbers])
while remaining_order > sub_max:
remaining_order -= np.product(package_numbers)
required_packages.append([max(package_numbers)]*np.product(package_numbers)/max(package_numbers))
Because if any package is in required_packages more often than (np.product(package_numbers)/i-1)*i it's sum is equal to np.product(package_numbers). In case the package max(package_numbers) isn't the one with the samllest price per unit, take the one with the smallest price per unit instead.
Example:
remaining_order = 100
package_numbers = [5,3]
Any part of remaining_order bigger than 5*2 plus 3*4 = 22 can be sorted out by adding 5 three times to the solution and taking remaining_order - 5*3.
So remaining order that actually needs to be calculated is 10. Which can then be solved to beeing 2 times 5. The rest is filled with 6 times 15 which is 18 times 5.
In case the number of possible package_numbers is bigger than just a handful, I recommend building a lookup table (with one of the others answers' code) for all numbers below sub_max which will make this immensely fast for any input.
add a comment |
In case you need a solution for a small number of possible
package_numbers
but a possibly very big
remaining_order,
in which case all the other solutions would fail, you can use this to reduce remaining_order:
import numpy as np
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
sub_max=np.sum([(np.product(package_numbers)/i-1)*i for i in package_numbers])
while remaining_order > sub_max:
remaining_order -= np.product(package_numbers)
required_packages.append([max(package_numbers)]*np.product(package_numbers)/max(package_numbers))
Because if any package is in required_packages more often than (np.product(package_numbers)/i-1)*i it's sum is equal to np.product(package_numbers). In case the package max(package_numbers) isn't the one with the samllest price per unit, take the one with the smallest price per unit instead.
Example:
remaining_order = 100
package_numbers = [5,3]
Any part of remaining_order bigger than 5*2 plus 3*4 = 22 can be sorted out by adding 5 three times to the solution and taking remaining_order - 5*3.
So remaining order that actually needs to be calculated is 10. Which can then be solved to beeing 2 times 5. The rest is filled with 6 times 15 which is 18 times 5.
In case the number of possible package_numbers is bigger than just a handful, I recommend building a lookup table (with one of the others answers' code) for all numbers below sub_max which will make this immensely fast for any input.
In case you need a solution for a small number of possible
package_numbers
but a possibly very big
remaining_order,
in which case all the other solutions would fail, you can use this to reduce remaining_order:
import numpy as np
remaining_order = 13
package_numbers = [9,5,3]
required_packages =
sub_max=np.sum([(np.product(package_numbers)/i-1)*i for i in package_numbers])
while remaining_order > sub_max:
remaining_order -= np.product(package_numbers)
required_packages.append([max(package_numbers)]*np.product(package_numbers)/max(package_numbers))
Because if any package is in required_packages more often than (np.product(package_numbers)/i-1)*i it's sum is equal to np.product(package_numbers). In case the package max(package_numbers) isn't the one with the samllest price per unit, take the one with the smallest price per unit instead.
Example:
remaining_order = 100
package_numbers = [5,3]
Any part of remaining_order bigger than 5*2 plus 3*4 = 22 can be sorted out by adding 5 three times to the solution and taking remaining_order - 5*3.
So remaining order that actually needs to be calculated is 10. Which can then be solved to beeing 2 times 5. The rest is filled with 6 times 15 which is 18 times 5.
In case the number of possible package_numbers is bigger than just a handful, I recommend building a lookup table (with one of the others answers' code) for all numbers below sub_max which will make this immensely fast for any input.
edited yesterday
answered yesterday
DonQuiKongDonQuiKong
200112
200112
add a comment |
add a comment |
Since no declaration about the object function is found, I assume your goal is to maximize the package value within the pack's capability.
Explanation: time complexity is fixed. Optimal solution may not be filling the highest valued item as many as possible, you have to search all possible combinations. However, you can reuse the possible optimal solutions you have searched to save space. For example, [5,5,3]
is derived from adding 3
to a previous [5,5]
try so the intermediate result can be "cached". You may either use an array or you may use a set to store possible solutions. The code below runs the same performance as the rosetta code but I think it's clearer.
To further optimize, use a priority set for opts
.
costs = [3,5,9]
value = [5,9,16]
volume = 130
# solutions
opts = set()
opts.add(tuple([0]))
# calc total value
cost_val = dict(zip(costs, value))
def total_value(opt):
return sum([cost_val.get(cost,0) for cost in opt])
def possible_solutions():
solutions = set()
for opt in opts:
for cost in costs:
if cost + sum(opt) > volume:
continue
cnt = (volume - sum(opt)) // cost
for _ in range(1, cnt + 1):
sol = tuple(list(opt) + [cost] * _)
solutions.add(sol)
return solutions
def optimize_max_return(opts):
if not opts:
return tuple()
cur = list(opts)[0]
for sol in opts:
if total_value(sol) > total_value(cur):
cur = sol
return cur
while sum(optimize_max_return(opts)) <= volume - min(costs):
opts = opts.union(possible_solutions())
print(optimize_max_return(opts))
If your requirement is "just fill the pack" it'll be even simpler using the volume for each item instead.
add a comment |
Since no declaration about the object function is found, I assume your goal is to maximize the package value within the pack's capability.
Explanation: time complexity is fixed. Optimal solution may not be filling the highest valued item as many as possible, you have to search all possible combinations. However, you can reuse the possible optimal solutions you have searched to save space. For example, [5,5,3]
is derived from adding 3
to a previous [5,5]
try so the intermediate result can be "cached". You may either use an array or you may use a set to store possible solutions. The code below runs the same performance as the rosetta code but I think it's clearer.
To further optimize, use a priority set for opts
.
costs = [3,5,9]
value = [5,9,16]
volume = 130
# solutions
opts = set()
opts.add(tuple([0]))
# calc total value
cost_val = dict(zip(costs, value))
def total_value(opt):
return sum([cost_val.get(cost,0) for cost in opt])
def possible_solutions():
solutions = set()
for opt in opts:
for cost in costs:
if cost + sum(opt) > volume:
continue
cnt = (volume - sum(opt)) // cost
for _ in range(1, cnt + 1):
sol = tuple(list(opt) + [cost] * _)
solutions.add(sol)
return solutions
def optimize_max_return(opts):
if not opts:
return tuple()
cur = list(opts)[0]
for sol in opts:
if total_value(sol) > total_value(cur):
cur = sol
return cur
while sum(optimize_max_return(opts)) <= volume - min(costs):
opts = opts.union(possible_solutions())
print(optimize_max_return(opts))
If your requirement is "just fill the pack" it'll be even simpler using the volume for each item instead.
add a comment |
Since no declaration about the object function is found, I assume your goal is to maximize the package value within the pack's capability.
Explanation: time complexity is fixed. Optimal solution may not be filling the highest valued item as many as possible, you have to search all possible combinations. However, you can reuse the possible optimal solutions you have searched to save space. For example, [5,5,3]
is derived from adding 3
to a previous [5,5]
try so the intermediate result can be "cached". You may either use an array or you may use a set to store possible solutions. The code below runs the same performance as the rosetta code but I think it's clearer.
To further optimize, use a priority set for opts
.
costs = [3,5,9]
value = [5,9,16]
volume = 130
# solutions
opts = set()
opts.add(tuple([0]))
# calc total value
cost_val = dict(zip(costs, value))
def total_value(opt):
return sum([cost_val.get(cost,0) for cost in opt])
def possible_solutions():
solutions = set()
for opt in opts:
for cost in costs:
if cost + sum(opt) > volume:
continue
cnt = (volume - sum(opt)) // cost
for _ in range(1, cnt + 1):
sol = tuple(list(opt) + [cost] * _)
solutions.add(sol)
return solutions
def optimize_max_return(opts):
if not opts:
return tuple()
cur = list(opts)[0]
for sol in opts:
if total_value(sol) > total_value(cur):
cur = sol
return cur
while sum(optimize_max_return(opts)) <= volume - min(costs):
opts = opts.union(possible_solutions())
print(optimize_max_return(opts))
If your requirement is "just fill the pack" it'll be even simpler using the volume for each item instead.
Since no declaration about the object function is found, I assume your goal is to maximize the package value within the pack's capability.
Explanation: time complexity is fixed. Optimal solution may not be filling the highest valued item as many as possible, you have to search all possible combinations. However, you can reuse the possible optimal solutions you have searched to save space. For example, [5,5,3]
is derived from adding 3
to a previous [5,5]
try so the intermediate result can be "cached". You may either use an array or you may use a set to store possible solutions. The code below runs the same performance as the rosetta code but I think it's clearer.
To further optimize, use a priority set for opts
.
costs = [3,5,9]
value = [5,9,16]
volume = 130
# solutions
opts = set()
opts.add(tuple([0]))
# calc total value
cost_val = dict(zip(costs, value))
def total_value(opt):
return sum([cost_val.get(cost,0) for cost in opt])
def possible_solutions():
solutions = set()
for opt in opts:
for cost in costs:
if cost + sum(opt) > volume:
continue
cnt = (volume - sum(opt)) // cost
for _ in range(1, cnt + 1):
sol = tuple(list(opt) + [cost] * _)
solutions.add(sol)
return solutions
def optimize_max_return(opts):
if not opts:
return tuple()
cur = list(opts)[0]
for sol in opts:
if total_value(sol) > total_value(cur):
cur = sol
return cur
while sum(optimize_max_return(opts)) <= volume - min(costs):
opts = opts.union(possible_solutions())
print(optimize_max_return(opts))
If your requirement is "just fill the pack" it'll be even simpler using the volume for each item instead.
edited yesterday
answered yesterday
knh190knh190
18412
18412
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54211693%2fpython-create-order-from-smaller-packages%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
As an aside, in Python, a
for
can have anelse
.– tripleee
Jan 16 at 7:13
1
Can you specify boundaries? Will it be 3 package sizes max or may there be 20000? Biggest input?
– DonQuiKong
yesterday
1
@BlueSheepToken lowest price I think, so 9. I'd even think that combination of biggest inputs should suffice, prices don't normally favor smaller package_sizes, but op should answer that.
– DonQuiKong
yesterday
1
@BlueSheepToken oh damn, you're right, the prices aren't quite logical. That .. basically reduces the possible input packages to 3 and 5 though in this case.
– DonQuiKong
yesterday
1
Which also means that trivially any input greater than 22 (2*5 + 4*3) can be solved by going mod 15 because necessarily there is either 3*5 or 5*3 in the solution which both is 15. Rest .. lut.
– DonQuiKong
yesterday