Find cheapest combination of items with total value greater or equal to a target value - knapsack-problem

EDIT: I've realized my question is a variant of the knapsack problem, only instead of maximum price and weight <= target, minimum price and length >= target. I'll try figuring it out and post an answer once I do.
Given an array of items, where each item has two properties - price and value,
I need to find the cheapest combination (lowest total price) whose total value is greater than or equal to a target value.
An item may be chosen multiple times.
items = [{id:"a", v:10, p:8}, {id:"b", v:25, p:15}, {id:"c", v:45, p:20}]
target = 60
result = ["c","a"]
Any help would be greatly appreciated! Thanks!

Here
# Use format [price,value]
data = [[12,10],[13,19],[12,13]]
tmp = []
for i in data:
tmp.append(i[1]-i[0])
best_deal = max(tmp)
best_deal_locations = []
for i in range(len(tmp)):
if tmp[i] == best_deal:
best_deal_locations.append(data[i])
print('Best Deals Found:')
for i in best_deal_location:
print('Price: ${}, Value: ${}'.format(i[0],i[1]))

Related

Subset sum variation: find the subset that sums to >= target, with minimum overshoot

Given a set of positive integers, and a target sum k, find the subset that sums to exactly k or least exceeds k. (i.e. equal or minimal overshoot)
This problem is occurring in a real life business feature-request, and the set size is expected to usually range from 1 to 30. It has to be solvable by low-end-PCs within say 3 seconds, so I guesstimate that a bruteforce method probably couldn't handle much more than 10 input integers?
I've looked thru search hits related to subset sum and knapsack, but have not seen anyone discuss this >= variation yet.
This is a rather simple extension of the original program: we simply use the dynamic programming algorithm, but also store lists we generate if these are overshooting the original value.
We can for example implement such algorithm as:
def least_gt_subset_sum(items, k):
vals = [None]*(k+1)
vals[0] = ()
best_v = None
best_k = 0
for item in items:
for i in range(k-1, -1, -1):
if vals[i] is not None:
if i + item <= k and vals[i+item] is None:
vals[i+item] = (*vals[i], item)
if i + item > k and (best_v is None or i + item < best_v):
best_v = i + item
best_k = (*vals[i], item)
if vals[k] is not None:
return vals[k]
else:
return best_k
So here we use the same trick, but in case the value is higher than k, we do some bookkeeping, and store the best result. At the end, we look if there is a value that matches exactly, if not, we return the best set that was higher, otherwise we return the one that was exact.

How to mantain constant percentage while adding new values

I want to make an algorithm that distributes total number of entities into different categories using some ideal percentage. Lets say for example, that first category should contain 50.3% of all entities, second - 34.3%, third - 15.4%.
In some ideal conditions everything is good. I'm easily calculating desired value of entity for every category and then using some algorithm similar to this to maintain the right sum.
Small example:
All categories are empty
We are adding 100
To the first 50
To the second = 34
To the third = 16 (fixed by current algorithm, was 15)
BUT, at the some point category can already contain some entities which are not distributed according our ideal percentage! And I do not know what algorithm I should use in this case. This algorithm should distribute new entities using these rules:
After adding we should be as close as possible to ideal percentage. Deviations between ideal and actual percentage should be minimal and close to each other.
Algorithm CANT delete existing entities from any category. It should only distribute the new ones.
Example:
At start:
First is empty
Second contains 10
Third contains 40
We are adding 50
To the first 38
To the second 12
To the third 0 (too much entities here before adding)
Result:
First = 38; deviation = 12.3%
Second = 22; deviation = 12.3%
Third = 40; deviation = 24.6%
Do not ask me how I got 38 and 12, I've just tried different combinations until it seems right.
Any ideas about algorithm?
Following approach might work. Let us say you maintain 3 lists, 1 for each categories and a running avg (i.e current avg of the list) and total elements. The additional 2 elements are needed to make sure the complexity of adding elements remains constant.
Data Structure:
category_list {
items : []
average : float
count : int
}
category_list categories[3]; # 1 for each category
avg_distribution[3]; # this will hold the distribution allowed for each category
Algorithm:
addItems(int items[]) {
for item in items:
category = getCategory(item)
insertItem(category, item)
}
# This algo will identify the category to be inserted in constant time or the no.of categories available.
# For this scenario we can say it runs in O(1)
int getCategory(int item) {
minAvg = INT_MAX
minCat = 0
for cat in range(3):
category = categories[cat]
newAvg = (category.avg*(category.count)+item.value) / (category.count+1)
newAvg = newAvg - avg_distribution[cat]
# this is to make sure we consider only the deviation part and not the entire avg.
if newAvg < minAvg:
minAvg = minAvg
minCat = cat
return minCat
}
# This will insert item in a given category in O(1)
insertItem(category, item) {
category.items[category.count] = item.value
category.avg = (category.avg*(category.count)+item.value) / (category.count+1)
category.count++;
}
# This method is need to initially load all the elements in given category
loadAllItems(int items[], int category) {
category = categories[category]
for item in items:
insertItem(category, item)
}
Hope it help!

Finding the binary sub-tree that puts each element of a list into its own lowest order bucket

First, I have a list of numbers 'L', containing elements 'x' such that 0 < 'x' <= 'M' for all elements 'x'.
Second, I have a binary tree constructed in the following manner:
1) Each node has three properties: 'min', 'max', and 'vals' (vals is a list of numbers).
2) The root node has 'max'='M', 'min'=0, and 'vals'='L' (it contains all the numbers)
3) Each left child node has:
max=(parent(max) + parent(min))/2
min=parent(min)
4) Each right child node has:
max=parent(max)
min=(parent(max) + parent(min))/2
5) For each node, 'vals' is a list of numbers such that each element 'x' of
'vals' is also an element of 'L' and satisfies
min < x <= max
6) If a node has only one element in 'vals', then it has no children. I.e., we are
only looking for nodes for which 'vals' is non-empty.
I'm looking for an algorithm to find the smallest sub-tree that satisfies the above properties. In other words, I'm trying to get a list of nodes such that each child-less node contains one - and only one - element in 'vals'.
I'm almost able to brute-force it with perl using insanely baroque data structures, but I keep bumping up against the limits of my mental capacity to keep track of all the temporary variables I've used, so I'm asking for help.
It's even cooler if you know an efficient algorithm to do the above.
If you'd like to know what I'm trying to do, it's this: find the smallest covering for a discrete wavelet packet transform to uniquely separate each frequency of the standard even-tempered musical notes. The trouble is that each iteration of the wavelet transform divides the frequency range it handles in half (hence the .../2 above defining the max and min), and the musical notes have frequencies which go up exponentially, so there's no obvious relationship between the two - not one I'm able to derive analytically (or experimentally, obviously, for that matter), anyway.
Since I'm really trying to find an algorithm so I can write a program, and since the problem is put in general terms, I didn't think it appropriate to put it in DSP. If there were a general "algorithms" group, then I think it would be better there, but this seems to be the right group for algorithms in the absence of such.
Please let me know if I can clarify anything, or if you have any suggestions - even in the absence of a complete answer - any help is appreciated!
After taking a break and two cups of coffee, I answered my own question. Indexing below is done starting at 1, MATLAB-style...
L=[] // list of numbers to put in bins
sorted=[] // list of "good" nodes
nodes=[] // array of nodes to construct
sortedidx=1
nodes[1]={ min = 0, max = 22100, val = -1, lvl = 1, row = 1 }
for(j=1;j<=12;j++) { // 12 is a reasonable guess
level=j+1
row=1
for(i=2^j;i<2^(j+1);i++) {
if(i/2 == int(i/2)) { // even nodes are high-pass filters
nodes[i]={ min = (nodes[i/2].min + nodes[i/2].max)/2, // nodes[i/2] is parent
max = nodes[i/2].max,
val = -1,
lvl = level,
row = -1
}
} else { // odd nodes are lo-pass
nodes[i]={ min = nodes[(i-1)/2].min,
max = (nodes[(i-1)/2].min+nodes[(i-1)/2].max)/2,
val = -1,
lvl = level,
row = -1
}
}
temp=[] // array to count matching numbers
tempidx=1
Lidx=0
for (k=1;k<=size(L);k++) {
if (nodes[i].min < L[k] && L[k] <= nodes[i].max) {
temp[tempidx++]=nodes[i]
Lidx=k
}
}
if (size(temp) == 1) {
nodes[i].row = row++
nodes[i].val = temp[1]
delete L[Lidx]
sorted[sortedidx++]=nodes[i]
}
}
}
Now array sorted[] contains exactly what I was looking for!
Hopefully this helps somebody else someday...

Algorithm for random numbers

I have to implement an algorithm for a raffle. The problem is that i would like that some of the participant to have more chances, because they have more points. How can i do that?
I thounght to simply put them many times in the raffle, but doesn't seems legit.
Do you know any algorithms that can do that?
Thanks
Pseudo algorithm:
winnerTicket <- a random number between zero and sum ticket count - 1
currentTicket <- 0
For each participant in participants ordered by id
If winnerTicket - currentTicket > participant.ticketCount
currentTicket += participant.ticketCount
Else
return participant
Why wouldn't that be "legit". If you base your amount of chance on a number of points, you add the person for X times in the raffle based on his points. That person's chance increase.
I would solve it in this way.
You have a mapping: participant => number of chances. In many programming languages you can declare a mapping or dictionary like this:
{"player1": 2, "player2": 5, ... many more like these}
so you can iterate like this:
accumulatedMap = {} #an empty map
total = 0
for each pair of key:count in the mapping:
total = total + count
accumulatedMap[key] = total
#now, get random and calculate
element = random between 1 and total, inclusive.
for each pair of key:accumulated in the mapping:
if element <= accumulated:
return key
#at this point, in the worst case the last key was returned.
This code is just an example. Remember that mappings don't always keep an insertion order when iterating.

Select a random item, without knowing the total number of items

I have a case where I need to select a random item, but I don't know the total number of items and I don't want to build a huge array then pick an item out. For example, this is what I have right now:
List<string> items;
while (true)
{
string item = GetNextItem();
if (item == null)
break;
}
int index = random.GetNext(0, items.count);
As you can see, I'm building a gigantic collection that I really don't need, I just need a random number between 0 and the number of items. Here is what I am thinking of doing, and it works, but I'd like to know if any of the experts out there can find a fault with it:
int index = -1;
int total;
string selectedItem;
while (true)
{
string item = GetNextItem();
if (item == null)
break;
++total;
int rnd = random.Next(0, total);
if (rnd == total- 1)
{
index = total- 1;
selectedItem = item;
}
}
This gives me my index number, and the randomly selected item. My thinking behind this is that when there are 3 total items, for example, I pick a random number between 0 and 2 (inclusive) and if it's equal to 2 I use the new item as the selected item, if not just ignore it. As the total number of items increases, each new item's chance of being selected decreases accordingly.
Is this method "good"? Is it as "random" as building the array and picking an item out later? Is it as fast as it can be? Please guide me through my ignorance in random numbers. :)
What you're doing will work.
Here's a restating of it that might make the algorithm slightly more clear:
Select the first item, there is a
100% chance it will be the current
selection
If there is a second item,
there is a 1/2 chance it will
replace the current selection (If you do the math, then it's a 50% chance it will be the first item, and a 50% chance it will be the second item)
If
there is a third item, there is a
1/3 chance it will replace the
current selection (again, the math the probability for each item being 1/3)
If there is a
fourth item, there is a 1/4 chance
it will replace the current
selection
... etc ...
Note that you should be able to compute a 1/x chance by saying rand.Next(0,x) == 0 (or any other integer between 0 and x - 1 inclusive; you don't have to bother using total - 1.
It's actually a pretty neat approach; initially I thought there wasn't going to be any good way of doing what you were asking!
Your approach looks good, yes.
1 item = gets selected
2 items = 50% chance you pick the 2nd item to replace the 1st
3 items = 33% chance you pick the 3rd item, 67% chance you pick one of first two items
4 items = 25% chance you pick 4th item, 75% chance you pick ...
...
So contrary to most of the other responses here I think you have a working solution that gives an even probability distribution.
You could simplify the random check:
int rnd = random.Next(0, total);
if (rnd == 0)
As it doesn't matter which of the total-1 values you test for to get the 1/n probability.
we can prove it by induction.
it is true for 1;
if it is true for n; it is true for n+1;
=> prob. of selection for first n elements = 1/n
=> sice prob. of selecting (n+1)th element is 1/(n+1)
=> prob of not selecting (n+1)th element is n/(n+1)
=> prob of selection for first n elements after adding (n+1)th element = 1/n*(n/n+1)=1/n+1
In your first code snippet, you use items.count, so you know how many elements you have. You need to know this number so that each element has an equal chance of being selected.
As you wrote, you generate a random number i such that 0 <= i < items.count, and then you try to quickly access element i of the list. (A linked list might not be a good choice of data structure.)
If you have a good estimate N of the number of items, you can use this instead of items.count.
In your second code snippet, you might have to initialize "total" to zero.

Resources