Here's some background of my problem(its not homework). I have a 4 items to choose from at a grocery store and I want to figure out what percentage of each I can fit in my basket but I set a range that no item can be less than 20% and no more than 60%. The program currently starts as 0 and works it way up(0 is the min value in this case 20, and anything above it equals how many percent over the min value it is). Using the above example of a min of 20, then [20,0,0,0]
would equal 40 + 20 + 20 + 20 = 100 and generates permutations for all the items.
After running it, I realized(using the above example) the first item is [20,0,0,0]
and the last item is [0,0,0,20]
. I tested it by comparing all the results against reversed versions of themselves and they all exist so I thought I could find a way to cut my processing time in half by only processing half the list then taking the results and flipping them around. I ran into a problem as I started checking for reversed matches while the program was still generating results, it seems there is not a single point where it flips over and starts duplicating(I was hoping exactly half way through it would do it). Here is the output of the results, the first column is the result itself and the second is the indexOf the reversed version of it(-1 means its not found). It starts off as all -1 and then starts to find a few reversed matches but still has many -1 then it eventually transitions over to having all repeated results but it seem to do it in a predictable clear cut way.
My end goal is to use larger lists and I'm trying to figure a way to generate the most data possible so any suggestions on how to identify the pattern or other speed improvements would be great. I'm thinking in this case I either need to have a method that identifies the pattern once its completely developed(i.e. no more chance of -1
) or tweak the algorithm so its generating in an order that switches over fully instead of a slow partial change.
if it helps, here's the code I'm using(note: the number of items and ranges are variables so I'm trying to find a general pattern and not specific to any hard numbers):
import java.util.*;
public class Distributor {
//correct output is 1771
private ArrayList<int[]> result = new ArrayList <int[]> ();
/*
*/
public Distributor (final String [] names, int [] low, int [] high)
{
final int rest = 100;
int minimum = 0;
for (int l : low)
minimum += l;
int [] sizes = new int [names.length];
distribute (0, low, high, rest - minimum, sizes);
System.out.println ("total size of results are " + result.size ());
}
public static void main (String [] args) {
System.out.println("starting..Hold on!!");
final String [] names = new String [] {"a", "b", "c", "d"}; //name of items
int [] low = new int [names.length];
int [] high = new int [names.length];
Arrays.fill(low, 20); //auto fill the range of items with a min/max range
Arrays.fill(high, 60);
new Distributor (names, low, high);
}
/*
distribute the rest of values over the elements in sizes, beginning with index i.
*/
void distribute (int i, int [] low, int [] high, final int rest, int [] sizes) {
if (i == sizes.length - 1) { //this area procesess the final item and adds it to the solution queue
if (rest < high [i]) {
sizes[i] = rest;
checkResultsDuringRuntime(Arrays.copyOf (sizes, sizes.length),result);
result.add (Arrays.copyOf (sizes, sizes.length));
}
}
else {
int StartLoop = 0;
//this area checks if the remaining value can be reached used the max values of remaining items
//if its not possible then the current min range of the loop must be increased
if ( rest > (low.length-(i + 1))*high[i]) {
System.out.println("rest is higher than high");
StartLoop = (rest - (low.length-(i + 1))*high[i]);
}
//this area runs a loop for each coeffient and then sends it back to this function to further processing
for (int c = StartLoop;
c <= java.lang.Math.min (high [i] - low [i], rest);
++c) {
sizes [i] = c;
distribute (i + 1, low, high, rest - c, sizes);
}
}
}
private static void checkResultsDuringRuntime(int[] defaultlist, ArrayList<int[]> result2) {
//check results list for list
//first lets flip the list around
int[] ReversedList = new int[defaultlist.length];
for (int x = defaultlist.length-1, y=0; x>=0;x--, y++) {
ReversedList[y] = defaultlist[x];
}
int MatchLocation = -1;
for (int[] item : result2) {
if ( Arrays.toString(item).equals(Arrays.toString(ReversedList)))
{
//System.out.println("theres a match");
MatchLocation = result2.indexOf(item);
}
}
System.out.println(Arrays.toString(defaultlist) + " = " + MatchLocation);
}
}
output: http://pastebin.com/6vXRvVit
Edit: The program is not generating duplicates. Its generating premuations that seem to reverse themselves eventually. I want to try to capture the point where the reversed permutation would all match existing results so instead of further processing the data I can just reverse existing results. Check out the output above for what I'm describing.