How to allocate x copy of n objects among k persons - algorithm

I have following use case;
I have N distinct items , each can have x number of copies. Now I need to distribute these items among k persons where each person's capacity is varying and can be <=N.
Following conditions must be met;
Each person should get one and only one copy of an Item
Example:
Items = apple , banana , orange
copies = 3 ( It means we have 3 apples , 3 bananas and 3 oranges )
So I have a array;
{1,2,3,4,5,6,7,8,9} // 1,2,3 = 3 apples ; 4,5,6 = 3 banana ; 7,8,9 = 3 oranges
Total Person = 5
Person Capacity
P1 3
P2 2
P3 1
P4 1
P5 2
How can I solve such problem ? The problem I am facing is that when I allocate it for an arbitrary numbers for N , x , k , I sometimes end up in a case where I am left with some items to allocate because I can't ensure the condition that "Each person should get one and only one copy of an Item"

Since each item has the same "weight", you can actually solve this problem greedily. To ensure that each person receives distinct items, we create the sequence containing all the xN items by repeating the sequence of N distinct items x times. Then, we go through each of the persons and simply remove and assign them the first c items of this sequence, where c is that person's carrying capacity.
This works because of the way we have laid out the items and because c <= N. In our "mega" sequence, duplicates are always N indices away from each other, so c consecutive elements will never contain two duplicates. Duplicates will only appear in contiguous subsequences containing more than N items.
Note that in the implementation of this algorithm, you don't actually have to create the mega sequence; you can simply repeatedly iterate through the distinct item sequence by using modular arithmetic. To keep the explanation simple, I will be forming the "mega" items sequence in the examples, but you don't have to do this in the implementation.
Taking the example in your question, let the 3 distinct items be A, B, C with 3 copies each. The "mega" sequence is formed by repeating the distinct items sequence 3 times: A, B, C, A, B, C, A, B, C. Now we go through each person and simply assign them the number of items they can carry. To illustrate this, consider the following cases for the capacity array (taken from your question and comments below):
[3, 2, 1, 1, 2]: P1 gets A, B, C, P2 gets A, B, P3 gets C, P4 gets A, and P5 gets B, C.
[2, 2, 2, 2, 1]: P1 gets A, B, P2 gets C, A, P3 gets B, C, P4 gets A, B, and P5 gets C.
[3, 1, 1, 1, 1, 2]: P1 gets A, B, C, P2 gets A, P3 gets B, P4 gets C, P5 gets A, P6 gets B, C.

Related

Solving chain reactions in prolog

One of the recent Advent of code challenges tasks me with solving for the smallest amount of input material that I can use to apply a given set of reactions and get 1 unit of output material.
For example, given
10 ORE => 10 A
1 ORE => 1 B
7 A, 1 B => 1 C
7 A, 1 C => 1 D
7 A, 1 D => 1 E
7 A, 1 E => 1 FUEL
We need 31 total ore to make 1 fuel (1 to produce a unit of B, then 30 to make the requisite 28 A).
This year, I've been trying to push my programming-language horizons, so I've done most of the challenges in SML/NJ. This one seems—seemed—like a good fit for Prolog, given the little I know about it: logic programming, constraint solving, etc.
I haven't, however, been able to successfully model the constraints.
I started by turning this simple example into some facts:
makes([ore(10)], a(10)).
makes([ore(1)], b(1)).
makes([a(7), b(7)], c(1)).
makes([a(7), c(1)], d(1)).
makes([a(7), d(1)], e(1)).
makes([a(7), e(1)], fuel(1)).
To be honest, I'm not even sure if the list argument is a good structure, or if the functor notation (ore(10)) is a good model either.
Then I wanted to build the rules that allow you to say, e.g., 10 ore makes enough for 7 a:
% handles the case where we have leftovers?
% is this even the right way to model all this... when we have leftovers, we may
% have to use them in the "reaction"...
makes(In, Out) :-
Out =.. [F,N],
Val #>= N,
OutN =.. [F,Val],
makes(In, OutN).
This works1, but I'm not sure it's going to be adequate, since we may care about leftovers (this is a minimization problem, after all)?
I'm stuck on the next two pieces though:
I can ask what makes 7 A and get back 10 ore, but I can't ask what is enough for 20 A: how do I write a rule which encodes multiplication/integer factors?
I can say that 7 A and 1 E makes 1 fuel, but I can't state that recursively: that is, I cannot state that 14 A and 1 D also make 1 fuel. How do I write the rule that encodes this?
I'm open to alternate data encodings for the facts I presented—ultimately, I'll be scripting the transformation from Advent's input to Prolog's facts, so that's the least of my worries. I feel that if I can get this small example working, I can solve the larger problem.
?- makes(X, a(7)). gives back X=[ore(10)] infinitely (i.e., if I keep hitting ; at the prompt, it keeps going). Is there a way to fix this?
Not a direct answer to your specific question but my first thought on this problem was to use chr in Prolog.
I then thought I would forward chain from fuel to the amount of ore I need.
The basic constraints:
:- chr_constraint ore/1, a/1, b/1,c/1, ab/1, bc/1, ca/1, fuel/0.
a(1),a(1) <=> ore(9).
b(1),b(1),b(1) <=> ore(8).
c(1),c(1),c(1),c(1),c(1) <=> ore(7).
ab(1) <=> a(3),b(4).
bc(1) <=> b(5),c(7).
ca(1) <=> c(4),a(1).
fuel <=> ab(2),bc(3),ca(4).
%Decompose foo/N into foo/1s
a(X) <=> X>1,Y#=X-1|a(Y),a(1).
b(X) <=> X>1,Y#=X-1|b(Y),b(1).
c(X) <=> X>1, Y#=X-1 | c(Y),c(1).
ab(X) <=> X>1, Y#=X-1|ab(Y),ab(1).
bc(X) <=> X>1,Y#=X-1| bc(Y),bc(1).
ca(X) <=> X>1, Y#= X-1| ca(Y),ca(1).
ore(X)<=>X >1, Y #= X -1 |ore(Y),ore(1).
%aggregation (for convenience)
:- chr_constraint ore_add/1, total_ore/1.
total_ore(A), total_ore(Total) <=> NewTotal #= A + Total, total_ore(NewTotal).
ore_add(A) ==> total_ore(A).
ore(1) <=> ore_add(1).
Query:
?-fuel.
b(1),
b(1),
c(1),
c(1),
ore_add(1),
ore_add(1),
...
total_ore(150).
Then you would need to add a search procedure to eliminate the two b/1s and two c/1s.
I have not implemented this but:
?-fuel,b(1),c(3).
ore_add(1),
...
total_ore(165)
This has only ore_add/1 constraints and is the correct result.
In the example there are no "alternative" path and no multiple "ore sources", so coding the example up in a very non-flexible way using Prolog can be done like this:
need(FUEL,OREOUT) :- need(FUEL,0,0,0,0,0,0,OREOUT).
need(FUEL,E,D,C,A,B,ORE,OREOUT) :- FUEL > 0, A2 is 7*FUEL+A, E2 is FUEL+E, need(0, E2, D, C, A2, B, ORE,OREOUT).
need(0,E,D,C,A,B,ORE,OREOUT) :- E > 0, A2 is 7*E+A, D2 is E+D, need(0, 0, D2, C, A2, B, ORE,OREOUT).
need(0,0,D,C,A,B,ORE,OREOUT) :- D > 0, A2 is 7*D+A, C2 is D+C, need(0, 0, 0, C2, A2, B, ORE,OREOUT).
need(0,0,0,C,A,B,ORE,OREOUT) :- C > 0, A2 is 7*C+A, B2 is C+B, need(0, 0, 0, 0, A2, B2, ORE,OREOUT).
need(0,0,0,0,A,B,ORE,OREOUT) :- X is A + B, X > 0, ORE2 is ORE + (A + 9)//10 + B, need(0, 0, 0, 0, 0, 0, ORE2,OREOUT).
need(0, 0, 0, 0, 0, 0, ORE, ORE).
Then
?- need(1011,ORE).
ORE = 3842
But this is just a silly and inelegant attempt.
There is a major general problem lurking thereunder, which includes parsing the arbitrarily complex reaction directed acyclic graph and building an appropriate structure. The good think is that it is a DAG, so one cannot generate an "earlier ingredient" from a "later one".
While making coffee, this is clearly something for the CLP(FD) engine.
If we have directed acyclic graph of reactions with
FUEL node on the right of the graph and
nodes for intermediate products IP[i] (i in 0..n) in between, with possibly
several FUEL nodes, i.e. several ways generating FUEL: FUEL[0] ... FUEL[v] and possibly
several nodes for intermediate products IP[i], i.e. several ways of creating intermediate product IP[i>0]: IP[i,1] ... IP[i,ways(i)] and
IP[0] identified with ORE on the left side of the graph
with the last two points giving us a way of choosing a strategy for the product mix, then:
FUEL_NEEDED = mix[0] * FUEL[0] + ... + mix[v] * FUEL[v]
with everything in the above a variable
and the following given by the problem statement, with FUEL[0] ... FUEL[v] variables and the rest constants:
out_fuel[0] * FUEL[0] = ∑_j ( IP[j] * flow(IPj->FUEL0) )
⋮
out_fuel[v] * FUEL[v] = ∑_j ( IP[j] * flow(IPj->FUELv) )
and for each IP[i>0], with the IP[i] variables and the rest constants:
out_ip[i] * IP[i] = ∑_j≠i ( IP[j] * flow(IPj->IPi) )
in case of a several ways to generate IP[i], we mix (this is like introducing a graph node for the mix of IP[i] from its possible ways IP[i,j]):
out_ip[i] * IP[i] = ∑_j(0..ways(i)) ( IP[i,j] * mix[i,j] )
out_ip[i,1] * IP[i,1] = ∑_j≠i ( IP[j] * flow(IP[j]->IP[i,1]) )
⋮
out_ip[i,ways(i)] * IP[i,ways(i)] = ∑_j≠i ( IP[j] * flow(IP[j]->IP[i,ways(i)]) )
and IP[0] (i.e. ORE) a free variable to be minimized.
You see an underspecified linear programming problem appearing here, with a matrix having zeroes below the diagonal because it's a DAG, but it contains variables to be optimized in the matrix itself. How to attack that?

Spacial clustering algorithm

Given a collection of points on a 2D plane, I want to find collections of X points that are within Y of each other. For example:
8|
7| a b
6|
5| c
4|
3| e
2| d
1|
-------------------------
1 2 3 4 5 6 7 8 9 0 1
a, b, c and d are points on the 2D plane. Given arguments of 3 for the number of points (X) and 3 for the distance (Y), the algorithm would return [[a, b, c]]. Some examples:
algorithm(X = 3, Y = 3) returns [[a, b, c]]
algorithm(X = 2, Y = 3) returns [[a, b, c], [d, e]] -- [a, b, c] contains at least two points
algorithm(X = 4, Y = 3) returns [] -- no group of 4 points close enough
algorithm(X = 5, Y = 15) returns [[a, b, c, d, e]]
Constraints:
x and y axis (the numbers above) are both 10,000 units long
there are 800 points (a, b, c, d etc) on the graph
I don't think it matters, but I'm using JavaScript
Things I've tried:
I actually care about outputting new points that are close to more than one input point, so I tried iterating on a grid and 'looking around' it using Pythagoras to find each point a given distance away. This is too slow given the total area. See the source here.
You can also see the data size in real data test.
DBSCAN, which seems to have a different purpose - I know how big I want my cluster size to be.
I'm currently trying to compare points to each other and build up close pairs, then close triplets, etc, until the end, but this seems to be going down a bit of an inefficiency hole also. I'm going to continue and try some kind of hashing or dictionary to avoid these loops.
With only 800 points, you can probably just build the graph by comparing each pair, then run Bron--Kerbosch to find maximal cliques. Here's a legit-seeming Javascript implementation of that algorithm: https://github.com/SeregPie/almete.BronKerbosch

Restricted combinations (algorithm)

Consider the following example:
I have a list of 5 items, each with their occurrence with either 1 or 0:
{a, b, c, d, e}
The restricted combinations are as follows:
the occurrence of a, c, and e cannot be 1 at any given time.
the occurrence of b, d, and e cannot be 1 at any given time.
basically, if found in database that occurrence of a and c is already 1, and if a given input is e (giving e an occurrence of 1) is not allowed (clause 1) or vice versa.
another example, d and e has an occurrence of 1 respectively in the database, a new input of b will not be allowed (following clause 2).
An even more solid example:
LETTER | COUNT(OCCURRENCE)
------------------------------
a | 1
b | 1
c | 1
d | 0
e | 0
Therefore, a new input of e would be rejected because of the violation of clause 1.
What is the best algorithm/practice for this solution?
I thought of having many if-else statements, but that doesn't seem efficient enough. What if I had a dynamic list of elements instead? Or at least have a better extensibility to this piece of program.
As mentioned by BKassem(I think) in the comments(removed for whatever reason).
The algorithm for this scenario:
(count(a) * count(c) * count(e)) == 0 //proceed to further actions
Worked flawlessly!

get all combinations of elements and elements can be repeat many times in single combination

I have a problem to get all combinations of elements, and elements can be repeat and reuse for many times, even in a single combination.
For example, I have a box with 100 cm2, then i have below objects:
1) Object A: 20cm2
2) Object B: 50cm2
The expected combinations would be: (A), (A, A), (A, A, A), (A, A, A, A), (A, A, A, A, A), (A, B), (A, B, A), (A, B, A, A) .....
Any combination are allowed, as long as they can fit into the box. Objects can be repeat many times in single combination. However, repeated pattern is not needed e.g. (A, B) is equal to (B, A).
I not sure what is the keyword to search for this question, do let me know if this is a repeated question.
Seems to me like a recursive algo would do the job: fit the first object then add all combinations of the next objects (including the one you just included) in the box with a reduced size.
Then do the same with the second object, always using combinations with the next objects in line, not the previous ones (can't have an A after a B).
With your example, you would have:
(A)
(A,A)
(A,A,A)
(A,A,A,A)
(A,A,A,A,A)
(A,A,A,A,B) does not work
(A,A,A,B) does not work
(A,A,B)
(A,B)
(A,B,B) does not work
(B)
(B,B)

Construction from many sets

I have four sets:
A={a,b,c}, B={d,e}, C={c,d}, D={a,b,c,e}
I want to search the sequence of sets that give me: a b c d
Example: the sequence A A A C can give me a b c d because "a" is an element of A, "b" is an element of A, "c" is an element of A and "d" is an element of C.
The same thing for : D A C B, etc.
I want an algorithm to enumerate all sequences possibles or a mathematical method to find the sequences.
You should really come up with some code of your own and then ask specific questions about problems with it. But it's interesting, so I'll share some thoughts.
You want a b c d.
a can come from A, D
b can come from A, D
c can come from A, C, D
d can come from B, C
So the problem reduces to finding all of the 2*2*3*2=24 ways to combine those options.
One way is recursion with backtracking. Build it from left to right, output when you have a complete set. Like the 8 queens problem, but much simpler since everything is independent.
Another way is to count the integers and map them into a mixed-base system. First digit base 2, then 2, 3, 2. So 0 becomes AAAB, 1 is AAAC, 2 is AACB, etc. 23 is DDDC and 24 needs five digits so you stop there.

Resources