How can I distribute weights knowing what's inside the box - algorithm

I have this problem and I think that I'm gonna need a mathematical solution.
I have some boxes. Of these, I only know their total weight and what is inside each one. I have to calculate each one's weight.
For example I have:
Total weight: 100
Number of boxes: 5
Number of items: 14
Stock:
Type1: 2 items
Type2: 1 items
Type3: 7 items
Type4: 4 items
Box #1:
Type1: 2 items
Type2: 1 items
Box #2:
Type4: 3 items
Box #3:
Type3: 3 items
Box #4:
Type3: 2 items
Type4: 1 items
Box #5:
Type3: 2 items
Each box can potentially have n types of items, so how can I distribute the total weight?
I cannot divide the total weight by the number of boxes because the result would be equal for all boxes and this is not a real case.

You have:
Four variables - the weight of each item type
One linear equation 2A + B + 7C + 4D = 100 - what you know about the total weight.
Some linear inequalities - you know that A, B, C and D are all positive.
There's an infinite number of possible solutions. For example A=B=C=2,D=20 or A=B=C=4,D=15 and everything in between.

Related

Divide items in each boxes that won't be 2 values has different items

Given an array a[] has n items and 2*k boxes. Each boxes can storage an infinity items, but in only one a[i]
Eg: if a[2]=5 and we divided to 3 boxes (b[1]=1,b[2]=2,b[3]=2), then 3 boxes 1,2,3 can't be storage any other value except a[2]
When we finished dividing all a[i] to 2k boxes. Maybe some box can be empty. We take k-minimum-box and calculate their sum (S). The question is: How to divide a[i] so that the sum (S) will be maximum.
Limit: N, K<=1000; A[i]<=1000
Example:
INP:
N=5; K=2; A[]={3,6,8,4,2}
OUT: 8
Explain:
We divided a[3]=8 in 2 boxes (b[1]=4; b[2]=4)
We put all a[4]=4 in 1 boxes (b[3]=4)
We put all a[2]=6 in 1 boxes (b[4]=6)
So the value of boxes are: {4,4,4,6}; 2-minimum-box is 4 and 4, the sum is 4+4=8
I have no idea about this problem except brute-forces (put each 1 in each box)

How to get max sum of k 2x1 or 1x2 tiles in Nx3 matrix

I have a problem where I have a N x 3 matrix with int values. I need to tile it with K 2x1 or 1x2 tiles so that they do not overlap and that I get the maximum sum with the use of dynamic programming.
What would the best way be to solve such a problem?
Example 5 x 3 matrix, K = 5:
2 6 2
6 5 6
2 6 2
1 1 1
1 1 1
Good tiles: (6,2), (6,2), (6,2), (6,5), (2,1)
Result = 38
And an example with an edge case:
2 x 3 Matrix, K = 2
0 4 1
3 4 1
Good tiles: (4,1), (4,3)
Result = 12
Let's define the state of a row as the cells that are covered by some of the K bricks. You have 8 combinations (2^3) from 000 (everything is not covered) to 111 (everything is covered) (you can use binary to encode the state for efficiency).
The dynamic programming matrix will be a[row][tiles][state]. Where row is the row we are processing, going top to bottom, tiles is how many tiles you placed already, state is the state as we defined above and the value is the current maximum sum.
To fill it we go top to bottom. We simplify things by only allowing a vertical tile to be placed on the current and the row above (not below). You can iterate through tile placement combinations between the rows (some are mutually exclusive). You have 3 vertical options and 2 horizontal options on the current row (5 options, for a total of 12 combinations, if I've done the math right). Also iterate through the possible values of 'titles'. For each combination look for all possible combination that allow it's placement on the previous row (so that the vertical tiles don't overlap) take the maximum and update the dynamic matrix. Some combinations are very strict (3 vertical tiles require 000 in the row above), while some are very relaxed (1 horizontal tile allows for every posibility). Do this on paper a few times to see how it works.
As an optimization note that you only need to know the values from the previous row, as the ones above that don't factor into so you can keep only the previous row and current row.
Algorithm should look something like this
For i from 0 to N
for tiles from 0 to K
for each combination
if tiles - combination.tiles < 0: continue
m = -1
for each state compatible with combination.previous_row
m = max(m, a[i-1][tiles - combination.tiles][state])
if m > 0
a[i][tiles][combination.state] = max(a[i][tiles][combination.state], m)
The solution is the maximum between the states on last row with tiles=K.
Complexity will be N*K* 12 combinations * 2^3 states so O(N*K). Memory can be O(K) with the trick I've mentioned above.

Modified Tower of Hanoi

We all know that the minimum number of moves required to solve the classical towers of hanoi problem is 2n-1. Now, let us assume that some of the discs have same size. What would be the minimum number of moves to solve the problem in that case.
Example, let us assume that there are three discs. In the classical problem, the minimum number of moves required would be 7. Now, let us assume that the size of disc 2 and disc 3 is same. In that case, the minimum number of moves required would be:
Move disc 1 from a to b.
Move disc 2 from a to c.
Move disc 3 from a to c.
Move disc 1 from b to c.
which is 4 moves. Now, given the total number of discs n and the sets of discs which have same size, find the minimum number of moves to solve the problem. This is a challenge by a friend, so pointers towards solution are welcome. Thanks.
Let's consider a tower of size n. The top disk has to be moved 2n-1 times, the second disk 2n-2 times, and so on, until the bottom disk has to be moved just once, for a total of 2n-1 moves. Moving each disk takes exactly one turn.
1 moved 8 times
111 moved 4 times
11111 moved 2 times
1111111 moved 1 time => 8 + 4 + 2 + 1 == 15
Now if x disks have the same size, those have to be in consecutive layers, and you would always move them towards the same target stack, so you could just as well collapse those to just one disk, requiring x turns to be moved. You could consider those multi-disks to be x times as 'heavy', or 'thick', if you like.
1
111 1 moved 8 times
111 collapse 222 moved 4 times, taking 2 turns each
11111 -----------> 11111 moved 2 times
1111111 3333333 moved 1 time, taking 3 turns
1111111 => 8 + 4*2 + 2 + 1*3 == 21
1111111
Now just sum those up and you have your answer.
Here's some Python code, using the above example: Assuming you already have a list of the 'collapsed' disks, with disks[i] being the weight of the collapsed disk in the ith layer, you can just do this:
disks = [1, 2, 1, 3] # weight of collapsed disks, top to bottom
print sum(d * 2**i for i, d in enumerate(reversed(disks)))
If instead you have a list of the sizes of the disks, like on the left side, you could use this algorithm:
disks = [1, 3, 3, 5, 7, 7, 7] # size of disks, top to bottom
last, t, s = disks[-1], 1, 0
for d in reversed(disks):
if d < last: t, last = t*2, d
s = s + t
print s
Output, in both cases, is 21, the required number of turns.
It completely depends on the distribution of the discs that are the same size. If you have n=7 discs and they are all the same size then the answer is 7 (or n). And, of course the standard problem is answered by 2n-1.
As tobias_k suggested, you can group same size discs. So now look at the problem as moving groups of discs. To move a certain number of groups, you have to know the size of each group
examples
1
n=7 //disc sizes (1,2,3,3,4,5,5)
g=5 //group sizes (1,1,2,1,2)
//group index (1,2,3,4,5)
number of moves = sum( g-size * 2^( g-count - g-index ) )
in this case
moves = 1*2^4 + 1*2^3 + 2*2^2 + 1*2^1 + 2*2^0
= 16 + 8 + 8 + 2 + 2
= 36
2
n=7 //disc sizes (1,1,1,1,1,1,1)
g=1 //group sizes (7)
//group index (1)
number of moves = sum( g-size * 2^( g-count - g-index ) )
in this case
moves = 7*2^0
= 7
3
n=7 //disc sizes (1,2,3,4,5,6,7)
g=7 //group sizes (1,1,1,1,1,1,1)
//group index (1,2,3,4,5,6,7)
number of moves = sum( g-size * 2^( g-count - g-index ) )
in this case
moves = 1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
= 64 + 32 + 16 + 8 + 4 + 2 + 1
= 127
Interesting note about the last example, and the standard hanoi problem: sum(2n-1) = 2n - 1
I wrote a Github gist in C for this problem. I am attaching a link to it, may be useful to somebody, I hope.
Modified tower of Hanoi problem with one or more disks of the same size
There are n types of disks. For each type, all disks are identical. In array arr, I am taking the number of disks of each type. A, B and C are pegs or towers.
Method swap(int, int), partition(int, int) and qSort(int, int) are part of my implementation of the quicksort algorithm.
Method toh(char, char, char, int, int) is the Tower of Hanoi solution.
How it is working: Imagine we compress all the disks of the same size into one disk. Now we have a problem which has a general solution to the Tower of Hanoi. Now each time a disk moves, we add the total movement which is equal to the total number of that type of disk.

0-1 Knapsack revisited

Well, this is an old 0-1 Knapsack problem but after finding the total maximum price I can get I need to find the the items I can carry. But for the following test case ( total 3 items)
10 (max weight that I can carry)
5 3 (weight and value for each item)
5 2
6 5
Here maximum price is 5. But for weight it can be 6 or 10(5+5) . Both will give the same price but obviously the feasible would be to take 6 kg item than 10 kg. I want hint how can I calculate this from the dp matrix. I got the following matrix for this test case.
0 0 0 0 3 3 3 3 3 3
0 0 0 0 3 3 3 3 3 5
0 0 0 0 3 5 5 5 5 5
Using this algo it finds weight as 10 but the optimal is 6 kg.
i=n, k=W(max weight)// n= total items
while i,k > 0
if dp[i,k] ≠ dp[i−1,k] then
mark the ith item as in the knapsack
i = i−1, k = k-w(weight of ith item)
else
i = i−1
Simple solution is to iteratively run the knapsack algorithm on varying bag sizes, and chose the smallest bag that still gives you the same value the original bag gave you.
This can be done using binary search on the weigths [0,W] - so you will run the knapsack algorithm total of O(logW) times, giving you total of O(nW*log(W)) solution that finds maximal value and minimal possible bag size.
Idea of how to imply the binary search:
Let the original bag be of size W, run knapsack(W,items), and get the value. Now check if knapsack(W/2,items) still returns value. If it does - search in range (0,W/2]. If it doesn't, search in range (W/2,W], until you find the smallest bag size that returns value.

User submitted rankings

I was looking to have members submit their top-10 list of something, or their top 10 rankings, then have some algorithm combine the results. Is there something out there like that?
Thanks!
Ahhhh, that's open-ended alright. Let's consider a simple case where only two people vote:
1 ALPHA
2 BRAVO
3 CHARLIE
1 ALPHA
2 DELTA
3 BRAVO
We can't go purely by count... ALPHA should obviously win, though it has the same votes as BRAVO. Yet, we must avoid a case where just a few first place votes dominate a massive amount of 10th place votes. To do this, I suggest the following:
$score = log($num_of_answers - $rank + 2)
First place would then be worth just a bit over one point, and tenth place would get .3 points. That logarithmic scaling prevents ridiculous dominance, yet still gives weight to rankings. From those example votes (and assuming they were the top 3 of a list of 10), you would get:
ALPHA: 2.08
BRAVO: 1.95
DELTA: .1
CHARLIE: .95
Why? Well, that's subjective. I feel out of a very long list that 4,000 10th place votes is worth more than 1,000 1st place votes. You may scale it differently by changing the base of your log (natural, 2, etc.), or choose a different system.
You could just add up the total for each item of the ranking given by a user and then sort them.
ie:
A = (a,b,c)
B = (a,c,b)
C = (b,a,c)
D = (c,b,a)
E = (a,c,b)
F = (c,a,b)
a = 1 + 1 + 2 + 3 + 1 + 2 = 10
b = 2 + 3 + 1 + 2 + 3 + 3 = 14
c = 3 + 2 + 3 + 1 + 2 + 1 = 12
Thus,
a
c
b
I think you could solve this problem by using a max flow algorithm, to create an aggregate ranking, assuming the following:
Each unique item from the list of items is a node in a graph. E.g. if there are 10 things to vote on, there are 10 nodes.
An edge goes from node *a* to node *b* if *a* is immediately before *b* in a _single user submitted_ ranking.
The last node created from a _single user submitted_ ranking will have an edge pointed at the *sink*
The first node created from a _single user submitted_ ranking will have an incoming edge from the *source*
This should get you an aggregated top-10 list.

Resources