Create all possible ways of putting n users into k groups - java

Given n users (u_1, u_2,..., u_n) and k groups (g_1, g_2, ..., g_k), create all possible combinations of all groups. basically, in the end, each combination is a Map<Integer,Integer>, where the first Integer is user ID, and the second Integer is group ID.For example, [(u_1,g_1), (u_2,g_1)....,(u_n, g_1)] is one possible combination.
There will be k^n combinations.
I searched and saw similar problems, but they do have some extra conditions that do not apply for my problem. In my case, there is no limit in each group, and there is no evenness or uniform distribution.
Can you suggest a quick way to do this in Java?
Thanks
My tries so far:
I tried to create a for loop for each possibility for each user, but I face the problem that I cannot define the number of for loops.
So I switched to recursion, but stuck at creating parameters for inside calls to the functions. Still working on it though.
Please, also note that this is not "n choose k". "n choose k" is when all users are identical, but here users are obviously not identical.
OK. I created a solution for this. Basically, it's a dynamic programming problem. Assume you have created a List of Maps (combinations) for j users and k locations. TO create for j+1 users and k locations, need 2 loop: for each Map, for each i=1 to k, Map.put(user_j+1, k)). Is is both recursive and iterative. Recursive because you need to pass the old maps to the new iterations. That's it.

The traditional solution to these kinds of problems is using recursion: If there are n = 0 users the only grouping possible is the empty group. Otherwise, take out the first user and generate the solution for the other n-1 users. Using the solution for the subproblem, generate the final solutions by assigning the first user to each of the k possible groups.
In code:
import java.util.*;
class Grouping {
public static void main(String[] args) {
List<?> groups = grouping(Arrays.asList(1,2,3), Arrays.asList(4,5,6,7));
System.out.println(groups.size());
System.out.println(groups);
}
static List<Map<Integer,Integer>> grouping(List<Integer> users, List<Integer> groups) {
if (users.isEmpty()) {
Map<Integer,Integer> empty = Collections.emptyMap();
return Collections.singletonList(empty);
} else {
Integer user = users.get(0);
List<Map<Integer,Integer>> subs = grouping(users.subList(1,users.size()), groups);
List<Map<Integer,Integer>> solutions = new ArrayList<>();
for (Integer group: groups) {
for (Map<Integer,Integer> sub : subs) {
Map<Integer,Integer> m = new HashMap<>(sub);
m.put(user, group);
solutions.add(m);
}
}
return solutions;
}
}
}

Ok, here is simple idea.
Lets first assume that each user_id is in {0, ... n-1}, and group_id is in {0, ... k-1}, we can map this numbers back to real ids later.
Now, what you basically want to do is to iterate thru all n-digit numbers in Base k numeral system, i.e. where each digit 0 <= base < k.
So, you start with number is 0000...00 (n-zeroes) and you end with kkkk....kk (n digits of nominal k). For each such number the position indicates user_id and digit value is this user's group_id.
So, the main workhorse you need to implement is the class Combination representing such n-digits sequence(try ArrayList or simple int[] array), with increment() operation implemented correctly (I imagine recursion is the best way to do this implementation). May be you could also have method isMaxReached() to check if all digits are of value k.
Then you would have a single loop :
Combination combination = new Combination(); // initialized with n -zeroes
while (!combination.isMaxReached()) {
combination.increment();
}
Please let me know if you would need more details on implementation.
Hope that helps.

It looks like we have the following:
n different numbers (users)
k sets (groups)
Objective is:
Find all the k-tuples with k sets S_k, such that for all i,j in 1..k the pairwise intersection of S_i and S_j is empty and the union S_1 .. S_k is the set 1..n
If this is what you want, then I would attack this recursively:
If n is 0, then the result is 1 k-tuple of empty sets.
If n is 1, then the results are k tuples, where for all elements S_j with j = 1..k it is the empty set except for the j-th element that is set {1}.
If n is m, then compute the list of tuples for m-1. Then replicate the list k times, and let the i-th set be the union of the i-th set and {n}. (Note that this is just a more general form of the previous rule for n=1).
Example:
n = 3, k = 2
n = 2, k = 2
n = 1, k = 2
n = 0, k= 2
result: [({},{})]
result: [({1},{}), ({},{1})]
result: [({1,2},{}), ({2},{1}), // j=1, union 1st with {2}
({1},{2}), ({},{1,2})] // j=2, union 2nd with {2}
result: [
({1,2,3},{}), ({2,3},{1}), ({1,3},{2}), ({3},{1,2}), // j=1, union 1st with {3}
({1,2},{3}), ({2},{1,3}), ({1},{2,3}), ({},{1,2,3}) // j=2, union 2nd with {3}
]

So u want maps like k1,n1, k1,nN .. kN,nN..
You will need 2 loops
Start by looping the groups . In each group, loop over all the users... and in the second loop , put(group,user) in a hashmap...
Code using the above algorithm.

Related

Print all possible combinations for a given array of elements

public class TestPossibleNumbers {
public static void main(String[] args) {
int input[] = { 1, 2, 3 };
// int input[] = {10,11,12,13};
possibleNumbers(input, 0);
}
public static void possibleNumbers(int[] x, int index) {
if (index == x.length) {
for (int i = 0; i < x.length; i++) {
System.out.print(x[i] + " ");
}
System.out.println();
}
for (int i = index; i < x.length; i++) {
int temp = x[index];
x[index] = x[i];
x[i] = temp;
possibleNumbers(x, index + 1);
temp = x[index];
x[index] = x[i];
x[i] = temp;
}
}}
Can anyone help me to understand the code inside for loop?
This program run perfectly. But, I am unable to figure out how it is working
You are recursively calling the method again at:
possibleNumbers(x, index + 1);
Thus the method runs the method again, with index + 1 passed. It checks if
if(index == x.length)
If the statement is correct it prints the numbers.
It then enters the 2nd for loop again(if the if statement was incorrect it will still enter it). And calls the recurring method again. It will keep entering 2nd for loop but when "index" will be equal to or greater than "i.length" no iterations of the for loop will run because you specified for loop to run only when:
i<i.length
When 2 for loop does not do any iterations the method will stop recurring. So in your case when index is equal to 3 no iterations of 2nd for loop will run.
Try running debug step by step to see what is happening more in depth.
The Program prints permutation of numbers not combination.
Permutation - Order matters
Combination - Order doesnt matter and more of choosing k elements out of n
for example
int a= {a,b};
permutation = {ab,ba}
whereas combination ={{},{a},{b},{a,b}}
To understand how the program works
go through the following link will
https://www.geeksforgeeks.org/write-a-c-program-to-print-all-permutations-of-a-given-string/
Don't get confused on recursion inside for loop.
if (index == x.length) is the terminating condition for recursion.
Inside the for loop before and after calling the recursive call possibleNumberselements are swapped.
Before swap helps to generate all possible outcomes and after swap elements will swap to previous position so that all other permutation will be generated from the for loop. It may sounds confusing please go through the link.
I'll provide an alternative explanation that I feel is more intuitive.
Consider the case of only 1 number in the list: [a]. This is pretty trivial: there's a single combination [a].
Now consider the case of 2 numbers in the list: [a, b]. In this case you can take each of the elements in turn and then look at all combinations of the remaining element using the previous method and then add the element back.
Now consider the case of 3 numbers in the list: [a, b, c]. In this case you can take each of the elements in turn and then look at all combinations of the other 2 elements using the previous method and then add the element back.
And so on for 3, 4, 5... elements.
So, in general, consider the case of n numbers in the list: [a1, a2, ... an]. In this case take each of the elements in turn and then look at all combinations of the other n-1 elements using the exact same method and then add the element back.
Converting to pseudo code:
getCombos(values)
for each value
for each combo in getCombos(values with value removed)
add value + combo to results
return results
The only thing to add is the base case which is necessary for all recursive implementations. One possibility is the case of a single item. However there's an even simpler one: if there are no values then the result is a single empty list.
So converting that to Java, using sets to make clear that the elements need to be unique (to avoid duplicate results), using streams and making it generic so it'll work for any type:
Stream<List<C>> combos(Set<C> values) {
if (values.isEmpty())
return Stream.of(new ArrayList<>());
else
return values.stream().flatMap(value ->
combos(values.stream()
.filter(v -> !v.equals(value))
.collect(toSet())).peek(r -> r.add(value)));
}
Your code is really just an alternate implementation of the same algorithm that swaps the element under consideration to the front of the array instead of creating a new collection.

Pseudo code: Random Permutation

I have a pseudo code that I have translated into java code but anytime I run the code, I get an empty arraylist as a result but it is supposed to give me a random list of integers.
Here is the pseudo code:
Algorithm 1. RandPerm(N)
Input: Number of cities N
1) Let P = list of length N, (|P|=N) where pi=i
2) Let T = an empty list
3) While |P| > 0
4) Let i = UI(1,|P|)
5) Add pi to the end of T
6) Delete the ith element (pi) from P
7) End While
Output: Random tour T
Here is the java code:
public static ArrayList<Integer> RandPerm(int n)
{
ArrayList<Integer> P = new ArrayList<>(n);
ArrayList<Integer> T = new ArrayList<>();
int i;
while(P.size() > 0)
{
i = CS2004.UI(1, P.size());// generate random numbers between 1 and the size of P
T.add(P.get(i));
P.remove(P.get(i));
}
return T;
}
I don't know what I am doing wrong.
ArrayList<Integer> p = new ArrayList<>(n);
... creates an empty list with an initial capacity of n.
All this does is tell the ArrayList what size array to initialise as backing store - most of the time you achieve nothing useful by specifying this.
So your while(p.size() > 0) runs zero times, because p.size() is zero at the start.
In the pseudocode "where pi=i" suggests to me that you want to initialise the list like this:
for(int i=0;i<n;i++) {
p.add(i)
}
(I have lowercased your variable name - in Java the convention is for variables to startWithALowerCaseLetter -- only class names StartWithUpperCase. It's also the Java convention to give variables descriptive names, so cityIdentifiers perhaps)
You may want to know that, even if you fix the problem that P is always empty, there are 2 more issues with your implementation.
One is that P.remove(P.get(i)) does not necessarily remove the ith item if the list has equal value items. It scans from the beginning and removes the first occurrence of the item. See ArrayList.remove(Object obj). You should use P.remove(i) instead for the correct results.
Then the performance is O(n^2). The reason is that ArrayList remove an item by shifting all the subsequent items one slot to the left, which is an O(n) operation. To get a much better performance, you can implement your own "remove" operation by swapping the item to the end. When you generate the next random index, generate it within the range [0, beginning index of the removed items at the end). Swapping is O(1) and the overall performance is O(n). This is called Knuth Shuffle by the way.

Allocating N tonnes of food in K rooms with M capacity

I found this problem online:
You have N tonnes of food and K rooms to store them into. Every room has a capacity of M. In how many ways can you distribute the food in the rooms, so that every room has at least 1 ton of food.
My approach was to recursively find all possible variations that satisfy the conditions of the problem. I start with an array of size K, initialized to 1. Then I keep adding 1 to every element of the array and recursively check whether the new array satisfies the condition. However, the recursion tree gets too large too quickly and the program takes too long for slightly higher values of N, K and M.
What would be a more efficient algorithm to achieve this task? Are there any optimizations to be done to the existing algorithm implementation?
This is my implementation:
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
public class Main {
// keeping track of valid variations, disregarding duplicates
public static HashSet<String> solutions = new HashSet<>();
// calculating sum of each variation
public static int sum(int[] array) {
int sum = 0;
for (int i : array) {
sum += i;
}
return sum;
}
public static void distributionsRecursive(int food, int rooms, int roomCapacity, int[] variation, int sum) {
// if all food has been allocated
if (sum == food) {
// add solution to solutions
solutions.add(Arrays.toString(variation));
return;
}
// keep adding 1 to every index in current variation
for (int i = 0; i < rooms; i++) {
// create new array for every recursive call
int[] tempVariation = Arrays.copyOf(variation, variation.length);
// if element is equal to room capacity, can't add any more in it
if (tempVariation[i] == roomCapacity) {
continue;
} else {
tempVariation[i]++;
sum = sum(tempVariation);
// recursively call function on new variation
distributionsRecursive(food, rooms, roomCapacity, tempVariation, sum);
}
}
return;
}
public static int possibleDistributions(int food, int rooms, int roomCapacity) {
int[] variation = new int[rooms];
// start from all 1, keep going till all food is allocated
Arrays.fill(variation, 1);
distributionsRecursive(food, rooms, roomCapacity, variation, rooms);
return solutions.size();
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int food = in.nextInt();
int rooms = in.nextInt();
int roomCapacity = in.nextInt();
int total = possibleDistributions(food, rooms, roomCapacity);
System.out.println(total);
in.close();
}
}
Yes, your recursion tree will become large if you do this in a naive manner. Let's say you have 10 tonnes and 3 rooms, and M=2. One valid arrangement is [2,3,5]. But you also have [2,5,3], [3,2,5], [3,5,2], [5,2,3], and [5,3,2]. So for every valid grouping of numbers, there are actually K! permutations.
A possibly better way to approach this problem would be to determine how many ways you can make K numbers (minimum M and maximum N) add up to N. Start by making the first number as large as possible, which would be N-(M*(K-1)). In my example, that would be:
10 - 2*(3-1) = 6
Giving the answer [6,2,2].
You can then build an algorithm to adjust the numbers to come up with valid combinations by "moving" values from left to right. In my example, you'd have:
6,2,2
5,3,2
4,4,2
4,3,3
You avoid the seemingly infinite recursion by ensuring that values are decreasing from left to right. For example, in the above you'd never have [3,4,3].
If you really want all valid arrangements, you can generate the permutations for each of the above combinations. I suspect that's not necessary, though.
I think that should be enough to get you started towards a good solution.
One solution would be to compute the result for k rooms from the result for k - 1 rooms.
I've simplified the problem a bit in allowing to store 0 tonnes in a room. If we have to store at least 1 we can just subtract this in advance and reduce the capacity of rooms by 1.
So we define a function calc: (Int,Int) => List[Int] that computes for a number of rooms and a capacity a list of numbers of combinations. The first entry contains the number of combinations we get for storing 0 , the next entry when storing 1 and so on.
We can easily compute this function for one room. So calc(1,m) gives us a list of ones up to the mth element and then it only contains zeros.
For a larger k we can define this function recursively. We just calculate calc(k - 1, m) and then build the new list by summing up prefixes of the old list. E.g. if we want to store 5 tons, we can store all 5 in the first room and 0 in the following rooms, or 4 in the first and 1 in the following and so on. So we have to sum up the combinations for 0 to 5 for the rest of the rooms.
As we have a maximal capacity we might have to leave out some of the combinations, i.e. if the room only has capacity 3 we must not count the combinations for storing 0 and 1 tons in the rest of the rooms.
I've implemented this approach in Scala. I've used streams (i.e. infinite Lists) but as you know the maximal amount of elements you need this is not necessary.
The time complexity of the approach should be O(k*n^2)
def calc(rooms: Int, capacity: Int): Stream[Long] =
if(rooms == 1) {
Stream.from(0).map(x => if(x <= capacity) 1L else 0L)
} else {
val rest = calc(rooms - 1, capacity)
Stream.from(0).map(x => rest.take(x+1).drop(Math.max(0,x - capacity)).sum)
}
You can try it here:
http://goo.gl/tVgflI
(I've replaced the Long by BigInt there to make it work for larger numbers)
First tip, remove distributionsRecursive and don't build up a list of solutions. The list of all solutions is a huge data set. Just produce a count.
That will let you turn possibleDistributions into a recursive function defined in terms of itself. The recursive step will be, possibleDistributions(food, rooms, roomCapacity) = sum from i = 1 to roomCapacity of possibleDistributions(food - i, rooms - 1, roomCapacity).
You will save a lot of memory, but still have your underlying performance problem. However with a pure recursive function you can now fix that with https://en.wikipedia.org/wiki/Memoization.

Finding all Logical Combinations of a Set

I am writing to ask if anyone knows how to go about this. I do not need the code, I would just like the logic behind doing this. So I have a set {A,B,C,D,E}. Now I want to find all combinations of and or OR operators amongst the values in the set.
Some examples below.
A and B and C and D and E
A and B and C and D or E
A and B and C or D and E
From what I know there is 2^n-1 possibilities in the case above. So in the specific example above we would have 8 combinations.
In addition to the Above the values in the set can have two possibilities. For simplicities sake lets say A can be True or False. Likewise B,C,D and E. So what we would potentially have is something like the following :
A=True and B=True and C=True and D=True and E=True
A=True and B=True and C=True and D=True and E=False
A=True and B=True and C=True and D=True or E=True
and so on. So taking this into account we would have 2^(2 * n-1) combinations. So in our specific example above again we would have 16 combinations for a set of 4.
Is there an algorithm that already does this? If not would anyone have some logic to implement this in Java
Thanks,
I think you're saying you want to enumerate (perhaps print) all the distinct expressions of the forms you have described, for some set size n. Since each one can be characterized by a set of flags (=True vs =False at positions 1 ... n, and And vs Or at positions 1 ... n - 1), you can represent each expression as an integer, with each flag corresponding to one (binary) bit. If n has a value for which you could hope to explicitly enumerate all the possibilities, such an integer will be well within the range of a Java long. For comfortably being able to enumerate all the possibilities, such an integer will be within the range of a Java int.
One way to proceed, therefore, would be to write a method to decode in-range integers into expressions according to their bit patterns. You can then iterate over all the appropriate integers (i.e. 0 ... (1 << (2 * n)) - 1), and decode each one into the corresponding expression.
If you have to get possible combination of five boolean values, you can do one thing -
Iterate a loop from zero to binary value "11111".
In each iteration you will get a unique combination of 0 and 1.
Convert 1 to true and 0 to false.
I hope below code will be helpful :
import java.util.ArrayList;
public class Test{
public static void main (String[] args)
{
ArrayList<boolean[]> result = new ArrayList<boolean[]>();
int max_num = Integer.parseInt("11111", 2);
for(int i=max_num; i>=0; i--)
{
String val = String.format("%5s", Integer.toBinaryString(i)).replace(' ', '0');
boolean[] arr = new boolean[5];
char[] charArray = val.toCharArray();
for(int j=0; j<charArray.length;j++)
{
if(charArray[j]=='1')
{
arr[j]=true;
}
else
{
arr[j]=false;
}
}
result.add(arr);
arr=null;
val=null;
}
for(int i=0;i<result.size();i++)
{
for(boolean b: result.get(i))
{
System.out.print(b+" ");
}
System.out.println();
}
}
}
To change the variable count :
Replace same count of 1 with "11111". e.g. if variable count is 6, it should be "111111"
Change "%5s" accordingly. e.g. if variable count is 6, it should be "%6s".
Initialize array "arr" with same count.

all possible ways in which K items can be arranged in N slots

I am looking for an algorithm to find all combinations of K values to n items.
Example:
K values are [R,B] & N is 2 so i get {RR, RB, BR, BB} 2*2 = 4 ways
K values are [R,B] & N is 3 so i get {RRR, RRB, RBB, RBR, BRR, BRB, BBR, BBB} 2*2*2 = 8 ways
I need to find out the generic algorithm to find all possible ways in which K items can be arranged in N slots. (repeat is allowed)
Another example would be:
K values are [R,G,B] & N is 5 so i need to find 3^5 = 81 combinations.
This problem lends itself exceptionally well to a recursive solution.
The solution in the general case is clearly formed by taking the solution for N - 1, and then prepending each of your set's elements in turn to the results. In pseudocode:
f(options, 0) = []
f(options, n) = options foreach o => o ++ f(options, n-1)
This could be implemented recursively in Java, but you'd run into stack overflow errors for moderately large values of n; and I also suspect the JIT compiler is less effective at optimising recursive algorithms so performance would suffer.
However, recursive algorithms can always be converted into a loop equivalent. In this case it might look something like:
List<String> results = new ArrayList<String>();
results.add(""); // Seed it for the base case n=0
for (int i = 0; i < n; i ++) {
List<String> previousResults = results;
results = new ArrayList<String>();
for (String s : options) {
for (String base : previousResults) {
results.add(s + base);
}
}
}
return results;
This works (I hope!) similarly to the recursive method - at each iteration it "saves" the current progress (i.e. the result for n-1) to previousResults, then just iterates over the options in turn, to get the result of prepending them to the previous results.
It would be interesting to see the effects of passing the recursive solution through any automatic recursion-to-iterative algorithms, and compare both the readability and performance to this hand-created one. This is left as an exercise for the reader.
I'll using counter of N bit in base k.
e.g: k=3, n=5
(0,0,0,0,0)
(0,0,0,0,1),
....
(2,2,2,2,2)
Implementing such a counter is easy, just keep array of size n+1, set all elements tozero at first, each time increase latest element, and if it will exceed from k-1, increase next neighbors (till neighbors are exceeding k-1). action terminates when n+1 element sets to 1.
If you tried and couldn't do so, tell it with comment.

Categories