Get sets of six unique combinations from an array given the range - arrays

I do have a problem, i have numbers from 1-49, now the question here is how do i get the maximum number of random sets of six from the given sample. like
int[] a1 = { 1, 2, 3 ,5,6,7 ... 49};
how many unique combination of numbers or arrays can i get from that one big array from 1 to 49 like below
1,2,3,4,5,6
2,1,4,5,8,9
2,1,0,2,4,5
................
What am trying to get is the maximum output or number of possible unique arrays with a length of six i could get . to be honest i have tried writing a loop that reads through the array, but how to capture six random digits is where am stuck i can go any further than
for(int x=0;<a1.length;x++)
{
// here i believe i must turn the captured information
// into a muti dimentional array to cpature like '1,2,3,4,5,6' but how. am stuck
}

If I understand your question correctly, what you need is the binomial coefficient n! / k! (n - k)!, which in this case would be 49! / (6! * (49 - 6)!) = 13983816. No need to write code if the only thing you want to know is the number of possible combinations.
If you really wanted to list all of them, you'd need a little patience. One way to achieve this is via a recursive approach:
public class NOverK {
private static final int[] numbers = new int[6];
private static final int MAX = 49;
private static void output() {
System.out.println();
for (int n : numbers) {
System.out.print(n + " ");
}
}
private static void allCombinations(int x, int start) {
if (x > 0) {
for (int i = start; i <= MAX; i++) {
numbers[numbers.length - x] = i;
allCombinations(x - 1, i + 1);
}
} else {
output();
}
}
public static void main(String[] args) {
allCombinations(6, 1);
}
}

This question has been asked at Stack Overflow a few times in the past. For example, look at this answer:
Click here: Algorithm to return all combinations of k elements from n
The answers to this question contain numerous solutions of your question in different programming languages (Java, Python, C, C# etc.), too. Check out or adjust a solution that meets your requirements.
You can search for other questions/answers in Stack Overflow (search field in upper right corner) with keywords
[algorithm] [combinations]
A Google search would lead to numerous solutions of your question, too. Try with keywords as follows:
java algorithm combinations without repetition
or
c# algorithm combinations without repetition

Related

How would I convert the data type int[] to the data type int

I have set up an array to randomize 5 different numbers in one class. In a different class I have prompted a user to guess the random number, and must reference the number each time to determine whether they have guessed correctly or not. My issue is that the numbers being randomized are in the data type int[], and I need to compare them to the data type int. When trying to reference the randomized numbers I get the error "Type mismatch: cannot convert from int[] to int". Any advice on how I would do that?
Class diceNumGen
final static int ARRAY_SIZE = 5;
public static int[] randNumArray = new int [ARRAY_SIZE];
public static int[] randNums(){
for(int i=0; i < randNumArray.length; i++) {
randNumArray[i] = (int) (Math.random()*12);
System.out.println(randNumArray);
}
return randNumArray.clone();
}}
Class Bet
static Bet bet = new Bet();
diceNumGen newClassObj = new diceNumGen();
int secondArray = diceNumGen.randNumArray;
//Set Turns variable where turns = 5
public int turnsToGo = 5;
//Set up the bet() method
public void bet() {
//Sets up the options as an array to be on the JOptionPane, each are numbered 0, 1, and 2 respectively
String[] options = {"Guess below 7", "Guess 7", "Guess above 7"};
welcome here, I'm newcomer too, this is my first answer.
I assume that you are using java, because of keywords, it is good to define the programming language in the question or tags to get better responses.
the first thing about your code is you don't need a whole class for generating an array, an ordinary function like this would be OK too:
static int[] randomGen(int len){
java.util.Random rand = new java.util.Random();
int[] randoms = new int[len];
for (int i = 0; i < len; i++) {
randoms[i] = rand.nextInt(12);
}
return randoms;
}
the next thing is, please indent your code, un-indented code (or badly indented code) will confuse the reader.
and about your question, at the first point why are you creating random array with the size of 5? if you just need one random number, just create one random number (with your Math.random() or better, nextInt(12) in Random class)
if user have 5 chances to guess same number you don't need 5 random numbers. just use this:
int randomNumber = (int) (Math.random() * 12);
or if you want user to guess 5 separate numbers, you need a for loop to iterate this random array per user guess.
Good luck in learning java.

How to use scanner to input into a 2 dimensional array?

I'm taking a online Java course and attempting my 2nd assignment. The first assignment was not difficult but this one is just way over top. I honestly don't know where to begin. The problem is this class is online, basic instructions are to read these chapters and then write the program. There's not much guidance since my instructor is not with me physically.
I've never used scanner before or created two dimensional arrays. My instructor gives notes on what to do in each area of his skeleton program but I don't have a clue which one to start with.
Your task is to implement a similar scheme to store poynomials of any number of terms, such that the
number of terms and the components (coefficient, variable and exponent) of every term are entered from
the keyboard.
To implement the interactive input we will using the Java class Scanner, defined in the java.utils
standard package. The Scanner class can be used in Java to read data types from a file. Since the input
console (keyboard) is treated as the file called System.in, we can create a Scanner for that input stream
as new Scanner (System.in), as shown below. Once you define a Scanner object, using its method
next() you can read Strings from the file/keyboard.
The incomplete program below is your assignment. You are supposed to complete without changing the
existing code.
Your output should be the terms of the polynomial entered by the user, separated by + signs.
Additional instructions in the code below, that you will change to achieve the requested functionality.
import java.util.Scanner;
public class Polynomials {
public static void storeTerm (int coeff, String var, int exp, String poly[][], int
where){
//ENTER THE COEFFICIENT, VARIABLE AND EXPONENT INTO THE
//ARRAY POLY THAT REPRESENTS THE POLYNOMIAL, AT POSITION "where"
//THAT RANGES BETWEEN INDEX 0 AND POLY.LENGTH-1
}
public static void printTerm (String [] term) {
//PRINTS EACH TERM
//IF THE EXPONENT OF THE VARIABLE IS 1 DOE NOT PRINT THE EXPONENT
//IF THE EXPONENT IS 0, PRINT ONLY THE COEFFCIENT
//IF THE COEFFICIENT IS 1, DO NOT PRINT IT, UNLESS IT IS THE ONLY COMPONENT OF
//THE TERM
}
public static void printPolynomial(String terms[][]){
//CALL printTerm in a loop to print all terms separated by + signs
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int numberTerms = 0;
System.out.println("How many terms?");
numberTerms = sc.nextInt();
//ENTER HERE THE CODE TO CREATE THE TWO DIMENSIONAL ARRAY NEEDED TO STORE THE TERMS
//OF THE POLYNOMIAL
if (numberTerms <= 0)
System.out.println("Error: Polynomials must have at least one term");
else {
String coeff = "", variable="", exponent="";
for (int i = 1; i<= numberTerms; i++) {
System.out.println("Enter the coeffcient for term " + i);
coeff = sc.next();
System.out.println("Enter the variable name:");
variable = sc.next();
System.out.println("Enter the expoenent for this term");
exponent = sc.next();
//CALL METHOD storeTerm TO INPUT THIS NEW TERM INTO THE ARRAY WRITE THE CORRECT
//CALL TO storeTerm HERE
}
printPolynomial(terms);
}//endf if
}//end main
}//end class
Again not looking for answers. Just where to start. Then I'll post my results.
It is not completely obvious where the two-dimensional array enters, since the structure hints at a list of terms.
You will need to define a data structure, in Java as a class, to hold the information for each term.
From the description, it seems that the input are polynomials of the form 3x^2+5y^7 and not xy+3y^2z^3.

How do i keep my program going?

Hey guys im making a game to help me study for finals. It is basically flash cards. I want the program to print out my question and answer by randomly selecting one. The thing is i dont want he same random number to be picked twice. how do i make sure the same number isn't picked twice till im out of questions? I am trying to make each random number be stored in blacklist so i can just check if the number is already in there before the program prints.
import java.util.ArrayList;
import java.util.Random;
public class Games {
static ArrayList<Integer> blacklist = new ArrayList<Integer>();
static int number;
static String[][] yes = {{"Apostolic Orgin", "Comes form the apostles"},
{"Biblical inerrancy", "the doctrine that the books are free from error reading the truth"},
{"Divine Inspiration", "the assistance the holy spirit gave the authors or the bible so they could write"},
{"fundamentalist approach", "interpretation of the bible and christian doctrine based on the literal meaning og bible's word"}, {"pentateuch", "first 5 books of old testament"}};
public static void main(String[] args) {
Printer(pickQuestion(), pickAnswer());
}
public static int RandomNumber(int i) {
int c;
Random r = new Random();
c = r.nextInt(i);
return c;
}
public static void Printer(String question, String answer) {
System.out.println("Question: " + question);
System.out.println("Answer: " + answer);
}
public static String pickQuestion() {
number = RandomNumber(yes.length);
return yes[number][0];
}
public static String pickAnswer() {
return yes[number][1];
}
}
The easiest option is to pre-shuffle the list of questions, either messing with the question and answer arrays directly, or by creating an array of integers from 1 to n where is the number of questions, shuffling that, and then loading the "card" in the position pointed to by that value in the array.
That is, create
[1,2,3,4,5]
Shuffle:
[5,1,3,4,2]
And load question 5, then question 1, etc.
This latter option would make a few things easier, not least of which is debugging!
Creating the array in order is a trivial for loop, and there are plenty of standard algorithms for shuffling too.
Random shuffling of an array

Sorting Numbers with arrays

Im really new to programming in Java so any answers don't be shy in really dumbing it down as much as possible.
I'm trying to create a program that will take an array value and sort it from smallest to largest number. This is what I've got so far:
public class ArraySwap
{
public static void main(String[] args)
{
int[a] = new int[4];
a[0] = 5;
a[1] = 7;
a[2] = 2;
a[3] = 1;
for (int i = a.length-1;
Thats what I've got so far, but I've no idea what to use in the for loop, it has to be an actual code formula with a for loop so no using array.sort or anything like that.
The output should re-arrange the numbers so they display 1 2 5 7 instead of 5 7 2 1 which is what they would be if I just had it print them out down the list.
My teacher gave me an example of what to use as this:
void swap (int x, int y)
{
int temp;
temp = x
x = y
y = temp;
}
But I have no idea how to use this in the program.
As mentioned by others, it would be good to read up on bubble sorting algorithms.
To answer your question, the swap function would be used every time two elements are out of order (when a larger number is before a smaller number). A pseudo-code example would be:
loop until no element changes through one cycle
for every element in the array minus one
if one element is greater than the element after it
swap()
And that is bubble sort! I hope this helps.
This is where you should use the simplest sorting algorithm in the world: Bubble Sort. Click here for the Wikipedia article describing step by step how to do it.
If you are still having trouble, leave a comment to this response.

Calculate all possibilities to get N using values from a given set [duplicate]

This question already has answers here:
Algorithm to find elements best fitting in a particular amount
(5 answers)
how do you calculate the minimum-coin change for transaction?
(3 answers)
Closed 9 years ago.
So here is the problem:
Given input = [100 80 66 25 4 2 1], I need to find the best combination to give me 50.
Looking at this, the best would be 25+25 = 50, so I need 2 elements from the array.
Other combinations include 25+4+4+4+4+4+4+1 and 25+4+4+4+4+4+2+2+1.. etc etc
I need to find all the possibilities which gives me the sum on a value I want.
EDIT: As well as the best possibility (one with least number of terms)
Here is what I have done thus far:
First build a new array (simple for loop which cycles through all elements and stores in a new temp array), check for all elements higher than my array (so for input 50, the elements 100,80,66 are higher, so discard them and then my new array is [25 4 2 1]). Then, from this, I need to check combinations.
The first thing I do is a simple if statement checking if any array elements EXACTLY match the number I want. So if I want 50, I check if 50 is in the array, if not, I need to find combinations.
My problem is, I'm not entirely sure how to find every single combination. I have been struggling trying to come up with an algorithm for a while but I always just end up getting stumped.
Any help/tips would be much appreciated.
PS - we can assume the array is always sorted in order from LARGEST to SMALLEST value.
This is the kind of problem that dynamic programming is meant to solve.
Create an array with with indices, 1 to 50. Set each entry to -1. For each element that is in your input array, set that element in the array to 0. Then, for each integer n = 2 to 50, find all possible ways to sum to n. The number of sums required is the minimum of the two addends plus 1. At the end, get the element at index 50.
Edit: Due to a misinterpretation of the question, I first answered with an efficient way to calculate the number of possibilities (instead of the possibilities themself) to get N using values from a given set. That solution can be found at the bottom of this post as a reference for other people, but first I'll give a proper answer to your questions.
Generate all possibilities, count them and give the shortest one
When generating a solution, you consider each element from the input array and ask yourself "should I use this in my solution or not?". Since we don't know the answer until after the calculation, we'll just have to try out both using it and not using it, as can be seen in the recursion step in the code below.
Now, to avoid duplicates and misses, we need to be a bit careful with the parameters for the recursive call. If we use the current element, we should also allow it to be used in the next step, because the element may be used as many times as possible. Therefore, the first parameter in this recursive call is i. However, if we decide to not use the element, we should not allow it to be used in the next step, because that would be a duplicate of the current step. Therefore, the first parameter in this recursive call is i+1.
I added an optional bound (from "branch and bound") to the algorithm, that will stop expanding the current partial solution if it is known that this solution will never be shorter then the shortest solution found so far.
package otherproblems;
import java.util.Deque;
import java.util.LinkedList;
public class GeneratePossibilities
{
// Input
private static int n = 50;
// If the input array is sorted ascending, the shortest solution is
// likely to be found somewhere at the end.
// If the input array is sorted descending, the shortest solution is
// likely to be found somewhere in the beginning.
private static int[] input = {100, 80, 66, 25, 4, 2, 1};
// Shortest possibility
private static Deque<Integer> shortest;
// Number of possibilities
private static int numberOfPossibilities;
public static void main(String[] args)
{
calculate(0, n, new LinkedList<Integer>());
System.out.println("\nAbove you can see all " + numberOfPossibilities +
" possible solutions,\nbut this one's the shortest: " + shortest);
}
public static void calculate(int i, int left, Deque<Integer> partialSolution)
{
// If there's nothing left, we reached our target
if (left == 0)
{
System.out.println(partialSolution);
if (shortest == null || partialSolution.size() < shortest.size())
shortest = new LinkedList<Integer>(partialSolution);
numberOfPossibilities++;
return;
}
// If we overshot our target, by definition we didn't reach it
// Note that this could also be checked before making the
// recursive call, but IMHO this gives a cleaner recursion step.
if (left < 0)
return;
// If there are no values remaining, we didn't reach our target
if (i == input.length)
return;
// Uncomment the next two lines if you don't want to keep generating
// possibilities when you know it can never be a better solution then
// the one you have now.
// if (shortest != null && partialSolution.size() >= shortest.size())
// return;
// Pick value i. Note that we are allowed to pick it again,
// so the argument to calculate(...) is i, not i+1.
partialSolution.addLast(input[i]);
calculate(i, left-input[i], partialSolution);
// Don't pick value i. Note that we are not allowed to pick it after
// all, so the argument to calculate(...) is i+1, not i.
partialSolution.removeLast();
calculate(i+1, left, partialSolution);
}
}
Calculate the number of possibilities efficiently
This is a nice example of dynamic programming. What you need to do is figure out how many possibilities there are to form the number x, using value y as the last addition and using only values smaller than or equal to y. This gives you a recursive formula that you can easily translate to a solution using dynamic programming. I'm not quite sure how to write down the mathematics here, but since you weren't interested in them anyway, here's the code to solve your question :)
import java.util.Arrays;
public class Possibilities
{
public static void main(String[] args)
{
// Input
int[] input = {100, 80, 66, 25, 4, 2, 1};
int n = 50;
// Prepare input
Arrays.sort(input);
// Allocate storage space
long[][] m = new long[n+1][input.length];
for (int i = 1; i <= n; i++)
for (int j = 0; j < input.length; j++)
{
// input[j] cannot be the last value used to compose i
if (i < input[j])
m[i][j] = 0;
// If input[j] is the last value used to compose i,
// it must be the only value used in the composition.
else if (i == input[j])
m[i][j] = 1;
// If input[j] is the last value used to compose i,
// we need to know the number of possibilities in which
// i - input[j] can be composed, which is the sum of all
// entries in column m[i-input[j]].
// However, to avoid counting duplicates, we only take
// combinations that are composed of values equal or smaller
// to input[j].
else
for (int k = 0; k <= j; k++)
m[i][j] += m[i-input[j]][k];
}
// Nice output of intermediate values:
int digits = 3;
System.out.printf(" %"+digits+"s", "");
for (int i = 1; i <= n; i++)
System.out.printf(" %"+digits+"d", i);
System.out.println();
for (int j = 0; j < input.length; j++)
{
System.out.printf(" %"+digits+"d", input[j]);
for (int i = 1; i <= n; i++)
System.out.printf(" %"+digits+"d", m[i][j]);
System.out.println();
}
// Answer:
long answer = 0;
for (int i = 0; i < input.length; i++)
answer += m[n][i];
System.out.println("\nThe number of possibilities to form "+n+
" using the numbers "+Arrays.toString(input)+" is "+answer);
}
}
This is the integer knapsack problem, which is one your most common NP-complete problems out there; if you are into algorithm design/study check those out. To find the best I think you have no choice but to compute them all and keep the smallest one.
For the correct solution there is a recursive algorithm that is pretty simple to put together.
import org.apache.commons.lang.ArrayUtils;
import java.util.*;
public class Stuff {
private final int target;
private final int[] steps;
public Stuff(int N, int[] steps) {
this.target = N;
this.steps = Arrays.copyOf(steps, steps.length);
Arrays.sort(this.steps);
ArrayUtils.reverse(this.steps);
this.memoize = new HashMap<Integer, List<Integer>>(N);
}
public List<Integer> solve() {
return solveForN(target);
}
private List<Integer> solveForN(int N) {
if (N == 0) {
return new ArrayList<Integer>();
} else if (N > 0) {
List<Integer> temp, min = null;
for (int i = 0; i < steps.length; i++) {
temp = solveForN(N - steps[i]);
if (temp != null) {
temp.add(steps[i]);
if (min == null || min.size() > temp.size()) {
min = temp;
}
}
}
return min;
} else {
return null;
}
}
}
It is based off the fact that to "get to N" you to have come from N - steps[0], or N - steps1, ...
Thus you start from your target total N and subtract one of the possible steps, and do it again until you are at 0 (return a List to specify that this is a valid path) or below (return null so that you cannot return an invalid path).
The complexity of this correct solution is exponential! Which is REALLY bad! Something like O(k^M) where M is the size of the steps array and k a constant.
To get a solution to this problem in less time than that you will have to use a heuristic (approximation) and you will always have a certain probability to have the wrong answer.
You can make your own implementation faster by memorizing the shortest combination seen so far for all targets (so you do not need to recompute recur(N, _, steps) if you already did). This approach is called Dynamic Programming. I will let you do that on your own (very fun stuff and really not that complicated).
Constraints of this solution : You will only find the solution if you guarantee that the input array (steps) is sorted in descending order and that you go through it in that order.
Here is a link to the general Knapsack problem if you also want to look approximation solutions: http://en.wikipedia.org/wiki/Knapsack_problem
You need to solve each sub-problem and store the solution. For example:
1 can only be 1. 2 can be 2 or 1+1. 4 can be 4 or 2+2 or 2+1+1 or 1+1+1+1. So you take each sub-solution and store it, so when you see 25=4+4+4+4+4+4+1, you already know that each 4 can also be represented as one of the 3 combinations.
Then you have to sort the digits and check to avoid duplicate patterns since, for example, (2+2)+(2+2)+(2+2)+(1+1+1+1)+(1+1+1+1)+(1+1+1+1) == (2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1). Six 2's and twelve 1's in both cases.
Does that make sense?
Recursion should be the easiest way to solve this (Assuming you really want to find all the solutions to the problem). The nice thing about this approach is, if you want to just find the shortest solution, you can add a check on the recursion and find just that, saving time and space :)
Assuming an element i of your array is part of the solution, you can solve the subproblem of finding the elements that sums to n-i. If we add an ordering to our solution, for example the numbers in the sum must be from the greater to the smallest, we have a way to find unique solutions.
This is a recursive solution in C#, it should be easy to translate it in java.
public static void RecursiveSum(int n, int index, List<int> lst, List<int> solution)
{
for (int i = index; i < lst.Count; i++)
{
if (n == 0)
{
Console.WriteLine("");
foreach (int j in solution)
{
Console.Write(j + " ");
}
}
if (n - lst[i] >= 0)
{
List<int> tmp = new List<int>(solution);
tmp.Add(lst[i]);
RecursiveSum(n - lst[i], i, lst, tmp);
}
}
}
You call it with
RecursiveSum(N,0,list,new List<int>());
where N is the sum you are looking for, 0 shouldn't be changed, list is your list of allowed numbers, and the last parameter shouldn't be changed either.
The problem you pose is interesting but very complex. I'd approach this by using something like OptaPlanner(formerly Drools Planner). It's difficult to describe a full solution to this problem without spending significant time, but with optaplanner you can also get "closest fit" type answers and can have incremental "moves" that would make solving your problem more efficient. Good luck.
This is a solution in python: Ideone link
# Start of tsum function
def tsum(currentSum,total,input,record,n):
if total == N :
for i in range(0,n):
if record[i]:
print input[i]
i = i+1
for i in range(i,n):
if record[i]:
print input[i]
print ""
return
i=currentSum
for i in range(i,n):
if total+input[i]>sum :
continue
if i>0 and input[i]==input[i-1] and not record[i-1] :
continue
record[i]=1
tsum(i+1,total+input[i],input,record,l)
record[i]=0
# end of function
# Below portion will be main() in Java
record = []
N = 5
input = [3, 2, 2, 1, 1]
temp = list(set(input))
newlist = input
for i in range(0, len(list(set(input)))):
val = N/temp[i]
for j in range(0, val-input.count(temp[i])):
newlist.append(temp[i])
# above logic was to create a newlist/input i.e [3, 2, 2, 1, 1, 1, 1, 1]
# This new list contains the maximum number of elements <= N
# for e.g appended three 1's as sum of new three 1's + existing two 1's <= N(5) where as
# did not append another 2 as 2+2+2 > N(5) or 3 as 3+3 > N(5)
l = len(input)
for i in range(0,l):
record.append(0)
print "all possibilities to get N using values from a given set:"
tsum(0,0,input,record,l)
OUTPUT: for set [3, 2, 2, 1, 1] taking small set and small N for demo purpose. But works well for higher N value as well.
For N = 5
all possibilities to get N using values from a given set:
3
2
3
1
1
2
2
1
2
1
1
1
1
1
1
1
1
For N = 3
all possibilities to get N using values from a given set:
3
2
1
1
1
1
Isn't this just a search problem? If so, just search breadth-first.
abstract class Numbers {
abstract int total();
public static Numbers breadthFirst(int[] numbers, int total) {
List<Numbers> stack = new LinkedList<Numbers>();
if (total == 0) { return new Empty(); }
stack.add(new Empty());
while (!stack.isEmpty()) {
Numbers nums = stack.remove(0);
for (int i : numbers) {
if (i > 0 && total - nums.total() >= i) {
Numbers more = new SomeNumbers(i, nums);
if (more.total() == total) { return more; }
stack.add(more);
}
}
}
return null; // No answer.
}
}
class Empty extends Numbers {
int total() { return 0; }
public String toString() { return "empty"; }
}
class SomeNumbers extends Numbers {
final int total;
final Numbers prev;
SomeNumbers(int n, Numbers prev) {
this.total = n + prev.total();
this.prev = prev;
}
int total() { return total; }
public String toString() {
if (prev.getClass() == Empty.class) { return "" + total; }
return prev + "," + (total - prev.total());
}
}
What about using the greedy algorithm n times (n is the number of elements in your array), each time popping the largest element off the list. E.g. (in some random pseudo-code language):
array = [70 30 25 4 2 1]
value = 50
sort(array, descending)
solutions = [] // array of arrays
while length of array is non-zero:
tmpValue = value
thisSolution = []
for each i in array:
while tmpValue >= i:
tmpValue -= i
thisSolution.append(i)
solutions.append(thisSolution)
array.pop_first() // remove the largest entry from the array
If run with the set [70 30 25 4 2 1] and 50, it should give you a solutions array like this:
[[30 4 4 4 4 4]
[30 4 4 4 4 4]
[25 25]
[4 4 4 4 4 4 4 4 4 4 4 4 2]
[2 ... ]
[1 ... ]]
Then simply pick the element from the solutions array with the smallest length.
Update: The comment is correct that this does not generate the correct answer in all cases. The reason is that greedy isn't always right. The following recursive algorithm should always work:
array = [70, 30, 25, 4, 3, 1]
def findSmallest(value, array):
minSolution = []
tmpArray = list(array)
while len(tmpArray):
elem = tmpArray.pop(0)
tmpValue = value
cnt = 0
while tmpValue >= elem:
cnt += 1
tmpValue -= elem
subSolution = findSmallest(tmpValue, tmpArray)
if tmpValue == 0 or subSolution:
if not minSolution or len(subSolution) + cnt < len(minSolution):
minSolution = subSolution + [elem] * cnt
return minSolution
print findSmallest(10, array)
print findSmallest(50, array)
print findSmallest(49, array)
print findSmallest(55, array)
Prints:
[3, 3, 4]
[25, 25]
[3, 4, 4, 4, 4, 30]
[30, 25]
The invariant is that the function returns either the smallest set for the value passed in, or an empty set. It can then be used recursively with all possible values of the previous numbers in the list. Note that this is O(n!) in complexity, so it's going to be slow for large values. Also note that there are numerous optimization potentials here.
I made a small program to help with one solution. Personally, I believe the best would be a deterministic mathematical solution, but right now I lack the caffeine to even think on how to implement it. =)
Instead, I went with a SAR approach. Stop and Reverse is a technique used on stock trading (http://daytrading.about.com/od/stou/g/SAR.htm), and is heavily used to calculate optimal curves with a minimal of inference. The Wikipedia entry for parabolical SAR goes like this:
'The Parabolic SAR is calculated almost independently for each trend
in the price. When the price is in an uptrend, the SAR emerges below
the price and converges upwards towards it. Similarly, on a
downtrend, the SAR emerges above the price and converges
downwards.'
I adapted it to your problem. I start with a random value from your series. Then the code enters a finite number of iterations.
I pick another random value from the series stack.
If the new value plus the stack sum is inferior to the target, then the value is added; if superior, then decreased.
I can go on for as much as I want until I satisfy the condition (stack sum = target), or abort if the cycle can't find a valid solution.
If successful, I record the stack and the number of iterations. Then I redo everything.
An EXTREMELY crude code follows. Please forgive the hastiness. Oh, and It's in C#. =)
Again, It does not guarantee that you'll obtain the optimal path; it's a brute force approach. It can be refined; detect if there's a perfect match for a target hit, for example.
public static class SAR
{
//I'm considering Optimal as the smallest signature (number of members).
// Once set, all future signatures must be same or smaller.
private static Random _seed = new Random();
private static List<int> _domain = new List<int>() { 100, 80, 66, 24, 4, 2, 1 };
public static void SetDomain(string domain)
{
_domain = domain.Split(',').ToList<string>().ConvertAll<int>(a => Convert.ToInt32(a));
_domain.Sort();
}
public static void FindOptimalSAR(int value)
{
// I'll skip some obvious tests. For example:
// If there is no odd number in domain, then
// it's impossible to find a path to an odd
// value.
//Determining a max path run. If the count goes
// over this, it's useless to continue.
int _maxCycle = 10;
//Determining a maximum number of runs.
int _maxRun = 1000000;
int _run = 0;
int _domainCount = _domain.Count;
List<int> _currentOptimalSig = new List<int>();
List<String> _currentOptimalOps = new List<string>();
do
{
List<int> currSig = new List<int>();
List<string> currOps = new List<string>();
int _cycle = 0;
int _cycleTot = 0;
bool _OptimalFound = false;
do
{
int _cursor = _seed.Next(_domainCount);
currSig.Add(_cursor);
if (_cycleTot < value)
{
currOps.Add("+");
_cycleTot += _domain[_cursor];
}
else
{
// Your situation doesn't allow for negative
// numbers. Otherwise, just enable the two following lines.
// currOps.Add("-");
// _cycleTot -= _domain[_cursor];
}
if (_cycleTot == value)
{
_OptimalFound = true;
break;
}
_cycle++;
} while (_cycle < _maxCycle);
if (_OptimalFound)
{
_maxCycle = _cycle;
_currentOptimalOps = currOps;
_currentOptimalSig = currSig;
Console.Write("Optimal found: ");
for (int i = 0; i < currSig.Count; i++)
{
Console.Write(currOps[i]);
Console.Write(_domain[currSig[i]]);
}
Console.WriteLine(".");
}
_run++;
} while (_run < _maxRun);
}
}
And this is the caller:
String _Domain = "100, 80, 66, 25, 4, 2, 1";
SAR.SetDomain(_Domain);
Console.WriteLine("SAR for Domain {" + _Domain + "}");
do
{
Console.Write("Input target value: ");
int _parm = (Convert.ToInt32(Console.ReadLine()));
SAR.FindOptimalSAR(_parm);
Console.WriteLine("Done.");
} while (true);
This is my result after 100k iterations for a few targets, given a slightly modified series (I switched 25 for 24 for testing purposes):
SAR for Domain {100, 80, 66, 24, 4, 2, 1}
Input target value: 50
Optimal found: +24+24+2.
Done.
Input target value: 29
Optimal found: +4+1+24.
Done.
Input target value: 75
Optimal found: +2+2+1+66+4.
Optimal found: +4+66+4+1.
Done.
Now with your original series:
SAR for Domain {100, 80, 66, 25, 4, 2, 1}
Input target value: 50
Optimal found: +25+25.
Done.
Input target value: 75
Optimal found: +25+25+25.
Done.
Input target value: 512
Optimal found: +80+80+66+100+1+80+25+80.
Optimal found: +66+100+80+100+100+66.
Done.
Input target value: 1024
Optimal found: +100+1+80+80+100+2+100+2+2+2+25+2+100+66+25+66+100+80+25+66.
Optimal found: +4+25+100+80+100+1+80+1+100+4+2+1+100+1+100+100+100+25+100.
Optimal found: +80+80+25+1+100+66+80+80+80+100+25+66+66+4+100+4+1+66.
Optimal found: +1+100+100+100+2+66+25+100+66+100+80+4+100+80+100.
Optimal found: +66+100+100+100+100+100+100+100+66+66+25+1+100.
Optimal found: +100+66+80+66+100+66+80+66+100+100+100+100.
Done.
Cons: It is worth mentioning again: This algorithm does not guarantee that you will find the optimal values. It makes a brute-force approximation.
Pros: Fast. 100k iterations may initially seem a lot, but the algorithm starts ignoring long paths after it detects more and more optimized paths, since it lessens the maximum allowed number of cycles.

Resources