recursion resulting in extra unwanted data - java

I'm writing a module to handle dice rolling. Given x die of y sides, I'm trying to come up with a list of all potential roll combinations.
This code assumes 3 die, each with 3 sides labeled 1, 2, and 3. (I realize I'm using "magic numbers" but this is just an attempt to simplify and get the base code working.)
int[] set = { 1, 1, 1 };
list = diceroll.recurse(0,0, list, set);
...
public ArrayList<Integer> recurse(int index, int i, ArrayList<Integer> list, int[] set){
if(index < 3){
// System.out.print("\n(looping on "+index+")\n");
for(int k=1;k<=3;k++){
// System.out.print("setting i"+index+" to "+k+" ");
set[index] = k;
dump(set);
recurse(index+1, i, list, set);
}
}
return list;
}
(dump() is a simple method to just display the contents of list[]. The variable i is not used at the moment.)
What I'm attempting to do is increment a list[index] by one, stepping through the entire length of the list and incrementing as I go.
This is my "best attempt" code. Here is the output:
Bold output is what I'm looking for. I can't figure out how to get rid of the rest. (This is assuming three dice, each with 3 sides. Using recursion so I can scale it up to any x dice with y sides.)
[1][1][1] [1][1][1]
[1][1][1] [1][1][2] [1][1][3] [1][2][3]
[1][2][1] [1][2][2] [1][2][3] [1][3][3]
[1][3][1] [1][3][2] [1][3][3] [2][3][3] [2][1][3]
[2][1][1] [2][1][2] [2][1][3] [2][2][3]
[2][2][1] [2][2][2] [2][2][3] [2][3][3]
[2][3][1] [2][3][2] [2][3][3] [3][3][3] [3][1][3]
[3][1][1] [3][1][2] [3][1][3] [3][2][3]
[3][2][1] [3][2][2] [3][2][3] [3][3][3]
[3][3][1] [3][3][2] [3][3][3]
I apologize for the formatting, best I could come up with.
Any help would be greatly appreciated. (This method was actually stemmed to use the data for something quite trivial, but has turned into a personal challenge. :)
edit: If there is another approach to solving this problem I'd be all ears, but I'd also like to solve my current problem and successfully use recursion for something useful.
edit2:
Running code including the "easy fix." Beware unused variables and weird hacks, I haven't cleaned it up yet.
package code.testing;
import java.util.ArrayList;
public class CodeTesting {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
int[] set = { 1, 1, 1 };
list = recurse(0,0, list, set);
}
public static ArrayList<Integer> recurse(int index, int i, ArrayList<Integer> list, int[] set){
if(index < 3){
// System.out.print("\n(looping on "+index+")\n");
for(int k=1;k<=3;k++){
// System.out.print("setting i"+index+" to "+k+" ");
set[index] = k;
if (index==2){
dump(set);
}
recurse(index+1, i, list, set);
}
}
return list;
}
static void dump(int[] arr) {
for (int s : arr) {
System.out.format("[%s]", s);
}
System.out.println();
}
}

I'm sorry I had to rewrite the code, but it's pretty much the same algorithm as yours with some corrections:
public class DiceRolls {
static void recurse(int diceNumber, int[] values, final int MAX) {
if (diceNumber == values.length) {
System.out.println(java.util.Arrays.toString(values));
} else {
for (int v = 1; v <= MAX; v++) {
values[diceNumber] = v;
recurse(diceNumber + 1, values, MAX);
}
}
}
public static void main(String[] args) {
recurse(0, new int[3], 4);
}
}
This is a standard tuplet recursive generator. If you want to add all the int[] into a List, then make sure to add(values.clone()) so they are independent int[] objects.
But what's with the extra output?
The problem is that you were dumping prematurely, before you're done throwing all the dices. In pseudocode, this is what you're doing:
if we're not done yet
trying all possibilities for this dice
dump result so far // premature dumping!
recurse for next dice
An easy fix to your code is to do the following:
if we're not done yet
trying all possibilities for this dice
recurse for next dice
else, we're done, so
dump result // timely!
So back to the Java implementation, the fix is merely moving dump(set); to an else case for the if (index < 3) statement.

Call dump() only when index == 2.
Incidentally, i and list seem unused. And the verb is "recur". :)

Here is a non-recursive alternative. Change the two constants to calculate all combinations for different dices and different numbers of dice.
package utils;
public class Dice {
private static int FACES = 3;
private static int NUMBER_OF_DICE = 3;
public static void main(String[] args) {
int start = createPair(1);
int end = createPair(FACES);
for (int i = start; i <= end; i++) {
String combination = Integer.toString(i, FACES+1);
if (combination.indexOf('0') < 0)
System.out.println(combination);
}
}
private static int createPair(int number) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < NUMBER_OF_DICE; i++) {
sb.append(number);
}
return Integer.parseInt(sb.toString(), FACES+1);
}
}

Related

How would I represent a 1D array into a 2D in the case of the 8 Queens Puzzle

So I have this basic N Queen Program solver.
It is made so that it gives all the possible solutions in 1 Array. In other words, if I get an array with values : {5,3,2,1,7,8,5,3}, it would mean that the first index represent the row and the value of that index its column.
My issue with this program is that I have tried to "graphically" represent a chessboard with the solution of that array on it. The method "printTable" is supposed to convert that 1D array into a 2D array following the rules I have explained. I then tried to to implement that method into the QueenSolve method. This is where it gets nasty.
I have tried the printTable method and it works perfectly on its own, however when I use it with the QueenSolve method, It doesn't give me the expected result.
I must have done something wrong with the array. If you compile this code below, you will see that the first solution to the 8 Queens puzzle is fine, however as you go along, you will see that some Queens start to go on top of each other, and in the end it is really messy.
I was just wondering if there was a solution to my problem. I understand that there must be an issue revolving around the result array. I tried to find some ways of dealing with that by storing the result array (aka one solution) with an array list and then go one from there, however I would get some different results.
If anyone could just have a look through this program and have it compile. I would appreciate any sort of help.
Thanks!
import java.util.Arrays;
import java.util.ArrayList;
public class NQueens {
static int[] result;
private int board[][]=new int[8][8];
private int N =8;
private int u=0;
public boolean QueenChecker(int x, int y) {
for (int i = 0; i < x; i++) {
if ((result[i] == y) || (Math.abs(i - x) == Math.abs(result[i] - y))) {
return false;
}
}
return true;
}
public void QueenSolve(int x) {
for (int i = 0; i < result.length; i++) {
if (QueenChecker(x, i)) {
result[x] = i; // place the queen at this position.
if (x == result.length - 1) {
printTable(result,N);
}
QueenSolve(x + 1);
}
}
}
public void printTable(int result[], int N)
{
for(int s=0;s<result.length;s++){
for (int u=0;u<result.length;u++)
{
board[s][result[s]]=1;
}
for(int j=0;j<result.length;j++){
if(board[s][j]==1)
System.out.print("Q");
else
System.out.print("*" );
}
System.out.println();//"\n");
}
}
public void AllSolutions(int j)
{
System.out.println("Solution : "+ j);
printTable(result,N);
System.out.println();
}
public static void main(String[] args) {
int n = 8;
result = new int[n];
NQueens i = new NQueens();
i.QueenSolve(0);
}
}
One problem you have is that you are never clearing your board.
A quick 'n dirty solution to your problem is to make sure at the beginning of your print method that you get a "fresh" board.
public void printTable(int result[], int N)
{
// Clear the board.
board = new int[8][8];
for(int s=0;s<result.length;s++){
for (int u=0;u<result.length;u++)
{
board[s][result[s]]=1;
}
for(int j=0;j<result.length;j++){
if(board[s][j]==1)
System.out.print("Q");
else
System.out.print("*" );
}
System.out.println();//"\n");
}
// Line at the end to separate the different boards from one another.
System.out.println("---------------------");
}
This is just an obvious problem I spotted right away. There might be more - I didn't check thoroughly. And the solution I'm offering is not best practice but rather just a quick 'n dirty one. Once you have it working as you expect, I suggest you head over to https://codereview.stackexchange.com/ to ask how you can improve your code.

how to find a number in a range in array

For example if I enter inRange(1,6) then it must print {2,2,2,3,5} for the below array. I am not sure if my logic is right. Is there a better way to do this? I am also not sure of how to construct my return statement. I want to do this without using arraylist or array.
public class AgeCount {
static int[] a=new int[]{1,2,45,6,3,2,1,2,5,6,65,45,43,21,34,34};
public AgeCount(){
}
public static int inRange(int b,int e)
{
int store[]=new int[a.length];
int count=0;
for (int i = 0; i < a.length; i++) {
if(a[i]>b && a[i]<e)
{
return a[i];
}
}
return 0;
}
If your method only has to print the numbers of the given range, it doesn't have to return anything :
public static void inRange(int b,int e)
{
int count=0;
System.out.print('{');
boolean first = true;
for (int i = 0; i < a.length; i++) {
if(a[i]>=b && a[i]<=e)
{
if (!first) {
System.out.print(',');
} else {
first = false;
}
System.out.print(a[i]);
}
}
System.out.print('}');
}
This is assuming the order of the output doesn't matter. If it does matter, sort the input array prior to the loop.
Java 8 approach:
int[] arr = new int[] {1,2,45,6,3,2,1,2,5,6,65,45,43,21,34,34};
int res[] = Arrays.stream(arr).filter(n -> n >= b && n <= e).toArray();
System.out.println(Arrays.toString(res));
I'm not sure why you don't want to use arrays or some kind of a list. If it's for homework purposes, then instead of returning a value from the method, print it if you only want to display the result. Otherwise, you should consider using List.
Java8:
public static void main(String[] args) {
int[] arrayToFilter = new int[]{1, 2, 45, 6, 3, 2, 1, 2, 5, 6, 65, 45, 43, 21, 34, 34};
int upperLimit = 5;
inRange(arrayToFilter, upperLimit);
}
private static void inRange(int[] arrayToFilter, int upperLimit) {
String sortedAndLimitedString = Arrays.stream(arrayToFilter)
.sorted()
.filter(value -> value < upperLimit)
.mapToObj(String::valueOf)
.collect(Collectors.joining(",", "{", "}"));
System.out.println(sortedAndLimitedString);
}
Output:
{1,1,2,2,2,3}
This sounds like a homework question. Still here goes.
Your return being a single int it has to be something like 122235 which represents all the ints satisfying your range condition.
So you use BitSet class and set the bits when found in range, which you can convert to an int like above and return.
I assumed that the result must be sorted.
public static int[] inRange(int b,int e) {
return IntStream.of(a)
.filter(n -> n > b && n < e)
.sorted()
.toArray();
}
System.out.println(Arrays.toString(AgeCount.inRange(1, 6)));
// -> [2, 2, 2, 3, 5]
```
Here is the simple & the shortest solution.
import java.util.*;
public class AgeCount
{
static int[] a=new int[]{1,2,45,6,3,2,1,2,5,6,65,45,43,21,34,34};
public AgeCount()
{
}
public static void inRange(int b,int e)
{
int store[]=new int[a.length];
Arrays.sort(a);
for (int i = b; i < e; i++)
{
System.out.print(a[i+1]+",");
}
}
}
And this is how you return a value for the same.
//sort an array, get a defined index values, and print it on the screen.
import java.util.*;
public class AgeCount
{
static int[] a=new int[]{1,2,45,6,3,2,1,2,5,6,65,45,43,21,34,34};
public AgeCount()
{
}
public static int[] inRange(int b,int e)
{
int store[]=new int[a.length];
int[] myRange = new int[e-b];
Arrays.sort(a);
for (int i = b; i < e; i++)
{
for (int j = 0; j < (e-b); j++)
{
myRange[j] = a[i+1];
}
System.out.print(a[i+1]+",");
}
return myRange;
}
}
Nice start so far! Even though you said you didn't want to use array or ArrayList, it makes the most sense here to use one. I would use an ArrayList of Integers instead of just an array, because we don't know the length yet. Instead of saying return a[i];, you would say store.append(a[i]);. I haven't tested this code, so there may be an error or two, so please correct me if I'm wrong, but here's the fixed version:
public class AgeCount {
static int[] a=new int[]{1,2,45,6,3,2,1,2,5,6,65,45,43,21,34,34};
public AgeCount(){
}
public static void inRange(int b,int e)
{
ArrayList<Integer> store = new ArrayList<Integer>();
int count=0;
for (int i = 0; i < a.length; i++) {
if(a[i]>=b && a[i]<=e)
{
store.append(a[i]);
}
}
println(store);
}
}
Well first things first, it seems like you aren't fully clear on what you are trying to do. And that's okay! Sometimes a problem can seem overwhelming and confusing if we're not really sure what's supposed to happen.
I recommend when you're starting a new task you take some time to decompose the task. Take a piece of paper and try and break it down into its smallest and simplest parts and go from there, coding and testing it bit by bit. The basics of the SDLC (try googling the software development lifecycle) could help you here too - it's all about figuring out what you are trying to achieve and what are the various things you need to implement to get there.
And please, Don't panic and throw code you don't understand down! You'll only sink deeper into the confusion!

java mergesort count homework

I am working on getting the counts of comparisons and movers when merge sorting. I think I have the recursion I need thanks to this Sort Comparisons Counter but I can not get it to print out. I am obviously very new at programming so I'd be appreciative if you could explain what it is that I am missing.
import java.util.Arrays;
public class MergeSort {
int count = 0;
/**
* #param args
*/
// Rearranges the elements of a into sorted order using
// the merge sort algorithm (recursive).
public int mergeSort(int[] a, int howMany) {
if (a.length >= 2) {
// split array into two halves
int[] left = Arrays.copyOfRange(a, 0, a.length/2);
int[] right = Arrays.copyOfRange(a, a.length/2, a.length);
// sort the two halves
howMany = mergeSort(left,howMany);
howMany = mergeSort(right, howMany);
// merge the sorted halves into a sorted whole
howMany = merge ( left, right, a, howMany);
}
return howMany;
}
// Merges the left/right elements into a sorted result.
// Precondition: left/right are sorted
public static int merge(int[] result, int[] left,
int[] right, int howMany) {
int i1 = 0; // index into left array
int i2 = 0; // index into right array
for (int i = 0; i < result.length; i++) {
if (i2 >= right.length ||
(i1 < left.length && left[i1] <= right[i2])) {
result[i] = left[i1]; // take from left
i1++;
} else {
result[i] = right[i2]; // take from right
i2++;
}
}
return howMany;
}
System.out.println(howMany); // ???
}
you need to call the method through its object wherever you wanna print. something like this (may be in your main method):
MergeSort mObj - new MergeSort();
int[] array = {1,2,3};
int count = mObj.mergeSort(array, 2);
System.out.println(count);
Basically, you need a driver method. When a java class is run, it will look for a public static void main(String[] args) method; if this method doesn't exist, nothing will happen. With what you have now, you should actually get a compile error from System.out.println(howMany); since the variable howMany only exists within the scope (brackets) of the merge method. To understand this better I'd review your notes on variable and method scope and class members. For a quick fix, remove the line at the bottom that I mentioned above, and place this method somewhere in your class:
public static void main(String[] args) {
int[] array = {2,5,8,1,3};
int howMany = mergeSort(array, 5);
System.out.println(howMany);
}
You also need to make your mergeSort method static, so change its definition to
public **static** int mergeSort(int[] a, int howMany)
I tested your code and I'm pretty sure that it doesn't give the answer you want, so be sure to check that. Best of luck learning object oriented programming!

Count how many times an element occurs in an array - Java

I recently made a very simple practice program in Python, that takes user input and rolls dice. The code is:
import random
import sys
import math
def roll(rolls, sides, results):
for rolls in range(1, rolls + 1):
result = random.randrange(1, sides + 1)
print result
results.append(result)
def countf(rolls, sides, results):
i = 1
print "There were", rolls, "rolls."
for sides in range(1, sides + 1):
if results.count(i) != 1:
print "There were", results.count(i), i,"s."
else:
print "There was", results.count(i), i
i = i + 1
if i == sides:
break
rolls = input("How many rolls? ")
sides = input("How many sides of the die? ")
results = []
roll(rolls, sides, results)
countf(rolls, sides, results)
(actually this is part of a larger program, so I had to cut'n'paste bits, and I might have missed something out).
And so I decided to translate that to Java. Notice the algorithm here: get random number, print it, append it to an array, then count the amount of each number in the array at the end, and print out that value. Problem is, I don't know how to do the equivalent of someArray.count(someIndex) in Java syntax. So my Java program looks like this so far:
import java.util.*;
public class Dice {
static Scanner input = new Scanner(System.in);
public static void main(String[] args) {
final static int TIMES_TO_ROLL = getInt("Times to roll?");
Random flip = new Random();
int[] results = new int[TIMES_TO_ROLL];
for (int i = 0; i < TIMES_TO_ROLL; i++) {
int result = flip.nextInt(6);
System.out.println(result);
results[i] = result;
}
}
public static int getInt(String prompt) {
System.out.print(prompt + " ");
int integer = input.nextInt();
input.nextLine();
return integer;
}
}
So can someone help me with the array counting code? I understand that this might not be a defined method, since Python is higher level after all, so I could make my own array counting method, but I was wondering if Java, like Python, has a predefined one.
EDIT: I managed something like this:
public static int arrayCount(int[] array, int item) {
int amt = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] == item) {
amt++;
}
else {
amt = amt;
}
}
return amt;
}
EDIT: Just out of interest, assuming I use Command prompt to run my Java program and Python.exe (command prompt console for Python), which one will be faster (in other words, for the same code, which language has better performance?)?
You could use a HashMap to store the result.
If the new number is not in your map you add it with "1" as initial value.
If it exists your put "+1" to the current map value.
To display the values you just have to iterate on you entries in a for each loop.
The solution is to transform your array to a List and then use the Collections.frequency method:
List<Integer> resultList = Arrays.asList(results);
int freq = Collections.frequency(resultList, 4);
Also you could use ArrayList from the very beginning saving you the transformation:
List<Integer> result = new ArrayList<Integer>();
// add results
int freq = Collections.frequency(result, 4);
See the Collections documentation here
EDIT: If performance is an issue (as suggested in the comments) then maybe you want to use each index of the array as a counter, as follows:
Random flip = new Random(SIDES);
int[] counters = new int[SIDES];
for (int i = 0; i < TIMES_TO_ROLL; i++) {
int result = flip.nextInt;
counters[result] = counters[result]+1;
}
Notice that you no longer need to count at the end since you've already got all the counters in the array and there is no overhead of calculating the hash.
There are a couple libraries that will do this for you:
Google Guava's MultiSet
Apache Common's Bag
But for something so simple, you may consider an extra library a bit excessive.
You can also do this yourself with an int[]. Assuming your dice is using whole numbers, have the number rolled refer to the index into the array, and then increment the value at that index. When you need to retrieve the value for a given number, look up its value by the index.
private static final int NUMBER_DICE_SIDES = 6;
public static void main(String[] args) {
final static int TIMES_TO_ROLL = getInt("Times to roll?");
Random flip = new Random(NUMBER_DICE_SIDES);
int[] results = new int[NUMBER_DICE_SIDES];
for (int i = 0; i < TIMES_TO_ROLL; i++) {
int result = flip.nextInt;
System.out.println(result);
results[result]++;
}
for(int i = 0; i < NUMBER_DICE_SIDES; ++i) {
System.out.println((i+1)+"'s: " + arraysCount(results, i));
}
}
public static int arrayCount(int[] array, int item) {
return array[item];
}
There's a frequency method in collections
int occurrences = Collections.frequency(listObject, searchItem);
Java doc for collections
As far as I am aware, there is no defined method to return the frequency of a particular element in an array. If you were to write a custom method, it would simply be a matter of iterating through the array, checking each value, and if the value matches the element you're after, incrementing a counter.
So something like:
// in this example, we assume myArray is an array of ints
private int count( int[] myArray, int targetValue) {
int counter = 0;
for (int i = 0 ; i < myArray.length; i++ ) {
if (myArray[i] == targetValue) {
counter++;
}
}
return counter;
}
Of course, if you want to find the frequency of all the unique values in your array, this has the potential of being extremely inefficient.
Also, why are you using a 7-sided die? The Random nextInt() will return a number from 0 up to but not including the max. So your die will return values from 0 through 6. For a six-sided die, you'd want a new Random(6); and then increment your roll by one to get a value from one through six: flip.nextInt() +1;.
class FindOccurrence {
public static void main (String[]args) {
int myArray[] = {5, 8, 5, 12, 19, 5, 6, 7, 100, 5, 45, 6, 5, 5, 5};
int numToFind = 5;
int numberOfOccurrence = 0;
for (int i=0; i < myArray.length; i++) {
if (numToFind == myArray[i]) {
numberOfOccurrence++;
}
}
System.out.println("Our number: " + numToFind);
System.out.println("Number of times it appears: " + numberOfOccurrence);
}
}

Creating a list of all possible percentages of items?

My goal is to give the program a few items(Strings), a range, and target percent and let it give me all possible percentages of each item. For example, Imagine you go to the grocery store and have a basket of Apples & Pears you want to know all the percentages you could have using ALL items(not a full solution, I'm doing this by hand):
{Apple:50, Pears:50}, {Apple:75, Pears:25}, {Apple:90, Pears:10},etc.
If I do the same thing with a range of 20-50(meaning the highest value a single item can have is 50% and the lowest 20%) then the only result is:
{Apple:50, Pears:50} (since there are only 2 items and it cannot exceed 50% weight)
I thought it had similar traits as an knapsack problem with a few big differences since there are no values/weights associated with the items(but like knapsack problem trying to fit items in a knapsack I’m trying to fit values within a target_percent, 100%). I’m also having trouble applying general dynamic programming ideas as well since I can’t figure out how to break the problem down(typical knapsack problems build up results and then ‘cache’ results to reuse but if if I have a list of X items, I need all X items to be used within a range).
I can do this via brute force but I don’t feel like its efficient because it just tries everything so the bounds that I’m using aren’t being used to make it efficient at all(for example if apple is 75% then there’s no reason Pear should exceed 25%..bounds are size of list, range, and target_percent..I might have 20-30 list items with a range of 5-20 or maybe 50 items with a range from 1-5..or anything in between I want to play around with how many complete results I can get as fast as possible. I have not shown the target_percent part in the question because I can set it up that once I understand how to solve the problem, but basically all the examples assume 100% max, but sometimes you may already have 20% oranges in your basket and see how you can use Apples/Pears to fill up the rest 80%).
My questions are, How can I approach this(any ideas logic to use, examples or proxy problems I can look up)? Is dynamic programming appropriate for this problem or the fact that I cannot break this into smaller chucks a problem(remember because its always includes all items in the list, its not building up)? If someone can point me to the right direction, I’m willing to study any topics that might help(After spending 2 days trying to figure this out,I’m just not sure if the Dynamic programming route is correct). Also is there a name for this type of problem(I looked up knapsack problems, integer partitioning, combinatorics but none of them seemed to fit)?
Here's my(broken) brute force approach(its not actually working as expected but maybe gives you an idea of the brute force method):
import java.util.ArrayList;
import java.util.Arrays;
public class brute_force_percent_returner {
static String[] data = new String[]{"Apple", "Pears"};
static int[] coeff = new int[data.length];
static ArrayList<int[]> queue = new ArrayList<int[]>();
public static void main(String[] args) {
System.out.println("Starting");
recursion(0,data);
for (int[] item : queue) {
for (int item2 = 0; item2<data.length; item2++) {
System.out.print(data[item2] + " = " + item[item2] + " ");
}
System.out.println();
}
}
private static void recursion(int k, String[] data2) {
// this is not exactly working
for (String item: data2) {
for (int x = 0; x<5;x++) {
int[] coeff_temp = Arrays.copyOf(coeff, coeff.length);
coeff_temp[k] = x;
queue.add(coeff_temp);
}
}
if (k == data.length-1) {
return;
} else {
recursion(k+1, data2);
}
}
}
If it helps the solution I was trying to create was somewhat based on this one(its a knapsack problem but seems to be super quick for large number of variables but in this care the items its processing are the items in the list whereas in my case the list is just strings):
public class TurboAdder {
private static final int[] data = new int[] { 5, 10, 20, 25, 40, 50 };
private static class Node {
public final int index;
public final int count;
public final Node prevInList;
public final int prevSum;
public Node(int index, int count, Node prevInList, int prevSum) {
this.index = index;
this.count = count;
this.prevInList = prevInList;
this.prevSum = prevSum;
}
}
private static int target = 100;
private static Node sums[] = new Node[target+1];
// Only for use by printString.
private static boolean forbiddenValues[] = new boolean[data.length];
public static void printString(String prev, Node n) {
if (n == null) {
System.out.println(prev);
} else {
while (n != null) {
int idx = n.index;
// We prevent recursion on a value already seen.
if (!forbiddenValues[idx]) {
forbiddenValues[idx] = true;
printString((prev == null ? "" : (prev+" + "))+data[idx]+"*"+n.count, sums[n.prevSum]);
forbiddenValues[idx] = false;
}
n = n.prevInList;
}
}
}
public static void main(String[] args) {
for (int i = 0; i < data.length; i++) {
int value = data[i];
for (int count = 1, sum = value; count <= 100 && sum <= target; count++, sum += value) {
for (int newsum = sum+1; newsum <= target; newsum++) {
if (sums[newsum - sum] != null) {
sums[newsum] = new Node(i, count, sums[newsum], newsum - sum);
}
}
}
for (int count = 1, sum = value; count <= 100 && sum <= target; count++, sum += value) {
sums[sum] = new Node(i, count, sums[sum], 0);
}
}
printString(null, sums[target]);
}
}
This sounds like homework so I'm extra reluctant to help you too much, but here's an approach.
to define the ranges, make a couple hash maps, like
lower bounds = {apples => 20, pears => 40, oranges => 0}
upper bounds = {apples => 50, pears => 100, oranges => 30}
if you think about it, every final (valid) combination would at the very least, have the contents defined by the lower bound map. so call that the base combination.
next, figure out the theoretical max of each type you can potentially add to the base combination. this is just another map
{apples => 30, pears => 60, oranges => 30}
figure how many total items you can add to the base map, which is 100 - the sum of all the lower bound values, in the example its 40.
now, you need to generate the combinations. You'll probably find recursion the easiest way to do it. ill demonstrate the remaining algorithm with pseudo code and hardcoded stuff to improve clarity, although you'll need to write a generic, recursive version of it.
totalItemsToAdd = 40 //as calculated via baseCombo.sumOfEntries()
for (i=0; i<maxApples; i++) {
combo = clone the base combination
combo.apples += i;
remainingItemsToAdd = totalItemsToAdd - i;
if (remainingItemsToAdd > 0) {
for (j=0; j<maxPears; j++) {
combo.pears += j;
// and so on, recursively
}
}
results.append(combo)
}
notice how it only generates valid combinations by keeping track of how many more items are possible for each of the combinations. So, this wouldnt be brute force, and it would actually do the minimum work needed to generate the set of combinations.
I'm pretty confident that the brute-force approach is the best way to go - at least, that's the way I would do it (which is by no means the same thing...).
Here's an attempt to work with the recursive approach that I've got working (although I haven't tested it with high values for weightsNo. This works on the basis that you're interested in the combinations of weights, rather than the permutations of weights - although the switch is relatively straightforward.
public static Set<int[]> getPossiblePercentageWeights(int weightsNo, int min, int max){
return recusiveFixWeight(weightsNo, 100, min, max);
}
private static Set<int[]> recusiveFixWeight(int weightsNo, int sum, int min, int max){
Set<int[]> weightsSet = new LinkedHashSet<int[]>();
if (weightsNo>2){
for (int iWeight=min; iWeight<=max; iWeight++){
Set<int[]> subSet = recusiveFixWeight(weightsNo-1, sum-iWeight, min, iWeight);
for (int[] subWeights : subSet){
int[] weights = new int[weightsNo];
weights[0] = iWeight;
System.arraycopy(subWeights, 0, weights, 1, subWeights.length);
weightsSet.add(weights);
}
}
} else {
int iMax = Math.min(max, sum/weightsNo);
for (int iWeight=min; iWeight<=iMax; iWeight++){
int jWeight = sum-iWeight;
if (jWeight>=min && jWeight<=max){
weightsSet.add(new int[]{iWeight,jWeight});
}
}
}
return weightsSet;
}
That said, having looked at the results, it looks like there should be an algorithm to determine how many weightSets there given a weightsNo, min and max, and from there it should be fairly straightforward to fill those in with possible values. That said, I can't quite figure it out at the moment. (Or indeed, whether it would be any quicker than the brute-force approach...)

Categories