USACO Training milking time (longest non-milking time) - java - java

I'm having trouble with Usaco training gate's milking time problem (aka milk2). My code works for the first few problems, but then doesn't work for one of the cases.
The problem is here:http://jeremiahflaga.blogspot.com/2011/09/milking-cows-programming-problem-from.html
The case that doesn't work is: [1, 2] [3, 4] [5, 6] [7, 8] [9, 10] [11, 12] [13, 14] [15, 16] [17, 18] [19, 20] [1, 20]
I think it is because of the last [1, 20], and it makes my code not work as I don't think I'm managing the merging correctly, but I've tried for some time and ended up making the code worse.
import java.io.*;import java.util.*;
public class milk2 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("milk2in.txt"));
PrintWriter pw = new PrintWriter(new File("milk2.out"));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
String line = "";
int milkInterval = 0;
int largestMilkInterval = 0;
int noMilkInterval = 0;
int largestNoMilkInterval = 0;
milkingTime[] times = new milkingTime[N];
for (int i = 0; i < times.length; i++) {
st = new StringTokenizer(br.readLine());
milkingTime mt = new milkingTime(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
times[i] = mt;
}
System.out.println(Arrays.toString(times));
for (int i = 0; i < times.length - 1; i++) {
noMilkInterval = 0;
if (times[i].getEnd() >= times[i + 1].getStart()) {
if (times[i].getStart() > times[i + 1].getStart()) {
milkInterval += times[i + 1].getEnd() - times[i + 1].getStart();
} else {
milkInterval += (times[i].getEnd() - times[i].getStart()) + (times[i + 1].getEnd() - times[i + 1].getStart());
}
System.out.println("Milk Interval: " + milkInterval);
} else {
milkInterval += (times[i].getEnd() - times[i].getStart());
if (milkInterval > largestMilkInterval) {
largestMilkInterval = milkInterval;
}
milkInterval = 0;
noMilkInterval += times[i + 1].getStart() - times[i].getEnd();
System.out.println("No milk interval: " + noMilkInterval);
}
if (noMilkInterval > largestNoMilkInterval) {
largestNoMilkInterval = noMilkInterval;
}
if (milkInterval > largestMilkInterval) {
largestMilkInterval = milkInterval;
}
}
if (times.length == 1) {
largestMilkInterval = times[0].getEnd() - times[0].getStart();
largestNoMilkInterval = 0;
}
System.out.println("Largest Milk Interval: " + largestMilkInterval);
System.out.println("Largest no milk Interval: " + largestNoMilkInterval);
// pw.println(largestMilkInterval + " " + largestNoMilkInterval);
// pw.close();
}
}
class milkingTime {
private int start;
private int end;
public milkingTime(int s, int e) {
start = s;
end = e;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
public String toString() {
return "Start: " + start + " End: " + end;
}
}
I also wonder if my code is just completely wrong, and this is not the correct direction of solving this problem.

Your solution seems wrong.
The main mistake is an assumption you apparently made, that you can find all important correlations between given intervals in a single pass along the table. Alas, the problem formulation makes no guarantee the intervals are given in any specific order. It even specifically mentions there are several 'farmers' milking – so their repective schedules may make a total input unordered when concatenated, even if each schedule is ordered. This is a case in your example data, which contains an ordered run of ten intervals
[1, 2] [3, 4] ... [19, 20]
and then another single-interval run
[1. 20]
which covers the former.
To handle that, I'd recommend sorting the data by a start time of intervals:
[1, 2] [1, 20] [3, 4] ... [19, 20]
Every two intervals with the same start time overlap, and now they sit in a contiguous block of the array, so we can easily find them. Additionally, an i-th interval overlaps some further k-th interval (with i less than k) if, and only if, the i-th one ends at the same time or later than the k-th one starts.
This is how I would merge them:
int curr = 0; // the interval to receive a merge
int next = 1; // the interval to be possibly merged into current
while (next < N)
{
if (times[curr].getEnd() >= times[next].getStart()) // overlapping?
{
times[curr].expandTo( times[next].getEnd() ); // merge to the current
}
else
{
++ curr; // finished merging to current
if (curr != next) // some items got merged
times[curr] = times[next]; // shift further items to emptied space
}
++ next;
}
newN = curr + 1; // number of separate intervals after all merges
Thanks to prior sorting we know the k-th interval can't start before the i-th one if i<k so the single condition reliably indicates all overlaps.
Of course the expandTo method in the milkingTime class must increase the end time to cover the given value:
class milkingTime {
.....
public void expandTo(int targetTime)
{
if (getEnd() < targetTime) {
setEnd(targetTime);
}
}
}
Now finding the longest interval and the longest gap is straight forward:
int longestInterval = 0;
for (int i = 0; i < newN; ++ i) {
if (times[i].getLength() > longestInterval)
longestInterval = times[i].getLength();
}
int longestGap = 0;
for (int i = 1; i < newN; ++ i) {
int gap = times[i].getStart() - times[i - 1].getEnd();
if (gap > longestGap)
longestGap = gap;
}

Related

How can I seperate an array into different 'mags'

I have this project that I have been working on, but I'm a bit rusty so I could use some help to figure out this part.
The main jizt of my project, is that I want to be able to fire a gun at a target and have the target analyze my data.
Before I even start on this, I did some research to find out if anyone else had done this before, and turns out a company in USA have done it, but in a different way than what I imagined..
This is not meant as a business idea, just a fun project for my self :)
Now here is my issue, I ofcourse made a "prototype" without the gun, and without the targets.
All text in Java to see if I could make this work.
I researched a bit since I was rusty (and still am), and figured out most of the problems I faced.
The part that has me stuck is at the very end of it, I have an array for all the shots but I want to divide this array into multiple arrays with the size of the magazine capacity.
How would I accomplish this?
Unfortunately I don't save my code, if I chose to delete it, so my scraps are long gone, but I have tried a few things that came to mind and for several days I havn't been able to figure this one out..
I tried with nested for loops, then I tried again but with nested for loops in a while loop, and I probably tried a few different things aswell.
if (hasrun == true) {
//OUTPUT
ms(2);
System.out.print("You shot the following:");
nl(1);
int counter = 0;
int i = 0;
while (sf > magcap) {
sf-=magcap;
mnm++;
}
while (counter <= mnm) {
System.out.print("Mag " + mn + ": ");
for (i+=0; i < magcap; i++) {
System.out.print(shots[i] + " ");
}
counter++;
mn++;
nl(1);
}
Just to clarify some things in my code here, I know this isn't the cleanest code, I'm not going for clean, and I know I don't need half of my functions (methods), but I did them to practice so they're there. Any help would be greatly appreciated with solving my problem tho! :)
If you want to have a look at all of my code for this project, head over to pastebin
You can use Guava to do it easily,
int[] x = {1,2,3,4,5,6};
int splitSize = 3;
List<Integer> list = IntStream.of(x).boxed().collect(Collectors.toList());
//partition
List<List<Integer>> partitioned = Lists.partition(list, splitSize);
//result: [[1,2,3], [4,5,6]]
Using System.arraycopy:
import java.util.Arrays;
public class Testing {
// static int[] input = {1,2,3,4,5,6}; // testdata
static int[] input = {1,2,3,4,5,6,7}; // testdata
// static int[] input = {1,2,3,4,5,6,7,8}; // testdata
static int magSize = 3; // testdata
// static int magSize = 5; // testdata
public static void main(String[] args) {
// int resultSize = (int) Math.ceil((double) input.length / magSize);
int resultSize = input.length % magSize == 0 ?
input.length/magSize :
input.length/magSize + 1;
int[][] result = new int[resultSize][magSize];
for (int i = 0; i < resultSize; i++) {
System.arraycopy(input, // src
i*magSize, // srcPos
result[i], // dest
0, // destPos
(i + 1) * magSize < input.length ?
magSize :
input.length - i*magSize); // length
}
System.out.println("Original : " + Arrays.toString(input));
System.out.println("Result : " + Arrays.deepToString(result));
/*
prints:
Original : [1, 2, 3, 4, 5, 6, 7]
Result : [[1, 2, 3], [4, 5, 6], [7, 0, 0]]
*/
}
}
I figured it somewhat out, here is what I did. Not quite implemented yet, but this worked with an array.
// OUTPUT
while (sf >= magcap) {
sf -= magcap;
mn++;
}
ms(2);
System.out.println(mn + " mags and " + sf + " shots fired");
nl(2);
for (int i = 0; i < mn; i++) {
from = magcap * magcounter - magcap;
to = magcap * magcounter;
System.out.print("Mag " + magcounter + ": ");
for (int j = from; j < to - 1; j++) {
System.out.print(shots[j] + ", ");
}
System.out.print(shots[to - 1] + ".");
magcounter++;
nl(1);
}
// PRINT THE REST
if (sf >= 1) {
from = magcap * magcounter - magcap;
to = magcap * magcounter;
if (sf == 1) {
System.out.print("Mag " + magcounter + ": ");
System.out.print(shots[from] + ".");
} else {
System.out.print("Mag " + magcounter + ": ");
for (int i = 0; i < sf - 1; i++) {
System.out.print(shots[from + i] + ", ");
}
from += sf -1;
System.out.print(shots[from] + ".");
}
}
The output is
1 2 3 4 5 6 7 8 9 10
3 mags fired and 1 shots fired
Mag 1: 1 2 3
Mag 2: 4 5 6
Mag 3: 7 8 9
Mag 4: 10

Any slice of array java

I tried to solve demo test in codility.
question:
A non-empty zero-indexed array A of N integers is given. A pair of integers (P, Q), such that 0 ≤ P ≤ Q < N, is called a slice of array A. The sum of a slice (P, Q) is the total of A[P] + A[P+1] + ... + A[Q].
A min abs slice is a slice whose absolute sum is minimal.
For example, array A such that:
A[0] = 2
A[1] = -4
A[2] = 6
A[3] = -3
A[4] = 9
contains the following slices, among others:
(0, 1), whose absolute sum = |2 + (−4)| = 2
(0, 2), whose absolute sum = |2 + (−4) + 6| = 4
(0, 3), whose absolute sum = |2 + (−4) + 6 + (−3)| = 1
(1, 3), whose absolute sum = |(−4) + 6 + (−3)| = 1
(1, 4), whose absolute sum = |(−4) + 6 + (−3) + 9| = 8
(4, 4), whose absolute sum = |9| = 9
Both slices (0, 3) and (1, 3) are min abs slices and their absolute sum equals 1.
I tried to go over all slices and did something like this:
class Solution {
public int solution(int[] A) {
int N = A.length;
if(N==1)
{
return A[0];
}
Arrays.sort(A);
for(int i=0;i<N; ++i)
{
System.out.println(A[i]);
}
int tail = 0;
int head = N - 1;
System.out.println(tail+ " "+head+"first");
long minAbsSum =(long) Math.abs(A[tail] + A[head]);
while (tail <= head) {
System.out.println(tail+ " "+head);
long currentSum = (long)A[tail] + (long)A[head];
minAbsSum = (long)Math.min(minAbsSum, Math.abs(currentSum));
// If the sum has become
// positive, we should know that the head can be moved left
if (currentSum <= 0)
tail++;
else
head--;
}
return (int)minAbsSum;
}
}
but I got slices of 2.
Is there some way that I could go over all the slices as requested in O(N*logN) complexity?
This isn't really the right forum to get help with your assignments. This is about helping developers with problems they encounter during development.
Setting this aside, your question seems to be about an algorithm that finds the mininmal absolute sum for any given slice of the provided array. As others have pointed out in the comments section, you "destroy" the sequence of values in your input array by sorting it. After the sorting you wont be able to reconstruct the sequence of values in the input array.
A possible solution with O(n^2) would be to iterate over all potential slices and remember the ones with the minimal absolute sum. To reduce the complexity to O(n log(n)) you could try to recursively split the input array into separate slices, calculate the sums for each and merge the results.
import java.util.HashSet;
import java.util.Set;
public class MinimalSliceSum {
private static int[] values = { 2, -4, 6, -3, 9 };
private static int minimalAbsSum = values[0];
private static Set<Slice> minimalSlices = new HashSet<>();
public static void main(String[] args) {
for (int i = 0; i < values.length; i++) {
int sum = 0;
for (int j = i; j < values.length; j++) {
sum += values[j];
processRange(i, j, sum);
}
}
System.out.println("Minimal abs sum: " + minimalAbsSum);
for (Slice slice : minimalSlices) {
System.out.println("Slice (" + slice.getFrom() + ", " + slice.getTo() + ")");
}
}
private static void processRange(int i, int j, int sum) {
int absSum = Math.abs(sum);
if (minimalAbsSum > absSum) {
minimalAbsSum = absSum;
minimalSlices.clear();
}
if (minimalAbsSum == absSum) {
minimalSlices.add(new Slice(i, j));
}
}
public static class Slice {
private int from;
private int to;
public Slice(int from, int to) {
this.from = from;
this.to = to;
}
public int getFrom() {
return from;
}
public int getTo() {
return to;
}
}
}

How to find repeating sequence of Integers in an array of Integers?

How to find repeating sequence of Integers in an array of Integers?
00 would be repeating, so would 123123, but 01234593623 would not be.
I have an idea to how to do this, but it is blurry in my mind, and my implementation doesn't go far due to this.
My idea was
Offset by a certain amount each time going through a for loop
Loop through inside of that and compare chunks of numbers by that offset
In Java, I got this far:
String[] p1 = new String[nDigitGroup];
String[] p2 = new String[nDigitGroup];
for (int pos = 0; pos < number.length - 1; pos++)
{
System.out.println("HERE: " + pos + (nDigitGroup - 1));
int arrayCounter = -1;
for (int n = pos; n < pos + nDigitGroup ; n++)
{
System.out.printf("\nPOS: %d\nN: %d\n", pos, n);
arrayCounter++;
p1[arrayCounter] = number[n];
System.out.println(p1[arrayCounter]);
}
pos += nDigitGroup;
arrayCounter = -1;
System.out.println("SWITCHING");
for (int n = pos; n < pos + nDigitGroup ; n++)
{
System.out.printf("\nPOS: %d\nN: %d\n", pos, n);
arrayCounter++;
p2[arrayCounter] = number[n];
System.out.println(p2[arrayCounter]);
}
if (p1[0].equals(p2[0]) && p1[1].equals(p2[1])) System.out.println("MATCHING");
}
When ran with these arguments:
repeatingSeqOf(2, new String[] {"1", "2", "3", "4", "5", "6", "7", "7" });
I am correctly filling the section arrays, but it breaks on an index out of bounds exception.
#MiljenMikic answer's is great, especially since the grammar isn't actually regular. :D
If you want to do it on an array in general, or want to understand it, this does pretty much exactly what the regex does:
public static void main(String[] args) {
int[] arr = {0, 1, 2, 3, 2, 3}; // 2, 3 repeats at position 2.
// for every position in the array:
for (int startPos = 0; startPos < arr.length; startPos++) {
// check if there is a repeating sequence here:
// check every sequence length which is lower or equal to half the
// remaining array length: (this is important, otherwise we'll go out of bounds)
for (int sequenceLength = 1; sequenceLength <= (arr.length - startPos) / 2; sequenceLength++) {
// check if the sequences of length sequenceLength which start
// at startPos and (startPos + sequenceLength (the one
// immediately following it)) are equal:
boolean sequencesAreEqual = true;
for (int i = 0; i < sequenceLength; i++) {
if (arr[startPos + i] != arr[startPos + sequenceLength + i]) {
sequencesAreEqual = false;
break;
}
}
if (sequencesAreEqual) {
System.out.println("Found repeating sequence at pos " + startPos);
}
}
}
}
You can always play with regular expressions to achieve a desired result. Use the regex backreference and combine it with the greedy quantifier:
void printRepeating(String arrayOfInt)
{
String regex = "(\\d+)\\1";
Pattern patt = Pattern.compile(regex);
Matcher matcher = patt.matcher(arrayOfInt);
while (matcher.find())
{
System.out.println("Repeated substring: " + matcher.group(1));
}
}
The answer posted by #AdrianLeonhard is perfectly working. But if I have a sequence of
0, 1, 2, 3, 4, 3, 5, 6, 4, 7, 8, 7, 8
many might be wondering on how to get all the repeated numbers from the array.
So, I wrote this simple logic which prints all the repeated numbers with their positions
int[] arr = {0, 1, 2, 3, 4, 3, 5, 6, 4, 7, 8, 7, 8};
for(int i=0; i<arr.length;i++){
for(int j=i+1; j<arr.length;j++){
if(arr[i] == arr[j]){
System.out.println("Number: "+arr[i]+" found repeating at position: "+i+" , repeated at position "+j);
}
}
}
Try this:
string lookIn = "99123998877665544123";
// above has length of 20 (in positions 0 through 19)
int patternLength = 3;
// want to search each triple of letters 0-2, 1-3, 2-4 ... 17-19
// however since there must be 3 chars after the 3-char pattern
// we only want to search the triples up to 14-16 (20 - 3*2)
for (int i=0; i <= lookIn.Length - patternLength * 2; i++) {
string lookingFor = lookIn.Substring(i, patternLength);
// start looking at the pos after the pattern
int iFoundPos = lookIn.IndexOf(lookingFor, i + patternLength);
if (iFoundPos > -1) {
string msg = "Found pattern '" + lookingFor
+ "' at position " + i
+ " recurs at position " + iFoundPos;
}
}
// of course, you will want to validate that patternLength is less than
// or equal to half the length of lookIn.Length, etc.
EDIT: improved and converted to javascript (from C# ... oops, sorry about that...)
function testfn() {
var lookIn = "99123998877665544123";
// above has length of 20 (in positions 0 through 19)
var patternLength_Min = 2;
var patternLength_Max = 5;
if (patternLength_Max > (lookIn.length / 2)
|| patternLength_Max < patternLength_Min
|| patternLength_Min < 1) {
alert('Invalid lengths.')
}
var msg = "";
for (var pLen = patternLength_Min; pLen <= patternLength_Max; pLen++) {
for (var i = 0; i <= lookIn.length - pLen * 2; i++) {
var lookingFor = lookIn.substring(i, i + pLen);
// start looking at the pos after the pattern
var iFoundPos = lookIn.indexOf(lookingFor, i + pLen);
if (iFoundPos > -1) {
msg = msg + "Found '" + lookingFor
+ "' at pos=" + i
+ " recurs at pos=" + iFoundPos + "\n";
;
}
}
}
alert(msg);
}
The message box displays the following:
Found '99' at pos=0 recurs at pos=5
Found '12' at pos=2 recurs at pos=17
Found '23' at pos=3 recurs at pos=18
Found '123' at pos=2 recurs at pos=17

Permutation - Need help desining a better block that won't need unused values

I need help making my permutation's (order important, repeatable) size smaller by discarding the unneeded permutations before hand.
The current permutation takes a global minimum and maximum from the values provided. However, some of the permutations are discarded afterward as they don't fall within the range needed.
The idea is there are for example 3 numbers which need a permutation. For example: 1-3, 8-10 and 5-15. The current code will create a permutation of 1-15 even though values from 4-7 will be discarded later on.
Unfortunately in some instances its not possible to create an array large enough in Java to contain the permutation results.
Any help would be appreciated on changing this permutation to only include necessary values prior to computing the permutation.
PermutationCore:
public class PermutationCore {
private String[] a;
private int n;
public PermutationCore(String[] arrayOfPossibilities, int lengthOfPermutation) {
this.a = arrayOfPossibilities;
this.n = lengthOfPermutation;
}
public String[][] getVariations() {
int l = a.length;
int permutations = (int) Math.pow(l, n);
Co.println("Permutation array size: " + permutations);
String[][] table = new String[permutations][n];
for (int x = 0; x < n; x++) {
int t2 = (int) Math.pow(l, x);
for (int p1 = 0; p1 < permutations;) {
for (int al = 0; al < l; al++) {
for (int p2 = 0; p2 < t2; p2++) {
table[p1][x] = a[al];
p1++;
}
}
}
}
return table;
}
}
Permutation
public class Permutation {
private ArrayList<Iteration> listOfIteration = new ArrayList<Iteration>();
private boolean prepared;
private PermutationCore permutationCore;
private int min = Integer.MAX_VALUE;
private int max = Integer.MIN_VALUE;
private int count = 0;
private String[][] arrayOfStringResults;
public void addIteration(Iteration iteration){
if (prepared){throw new IllegalStateException("Permuation is already prepared. Create a new instance to add new items");}
this.listOfIteration.add(iteration);
}
public void prepare(){
String[] arrayOfString;
for (Iteration iteration : listOfIteration){
if (iteration.end > max){max = iteration.end;}
if (iteration.start < min){min = iteration.start;}
}
arrayOfString = new String[max-min+1];
for (int i=0; i<arrayOfString.length; i++){
arrayOfString[i] = String.valueOf(min+i);
}
permutationCore = new PermutationCore(arrayOfString, listOfIteration.size());
prepared = true;
// Co.println("Min/max: " + min + "," + max);
arrayOfStringResults = permutationCore.getVariations();
// ArrayTools.sort2DStringArray(arrayOfStringResults);
}
public boolean iterate(){
LABEL_ITERATE_LOOP: {
int i=0;
if (count == arrayOfStringResults.length){
return false;
}
for (Iteration iteration : listOfIteration){
int currentValue = Integer.valueOf(arrayOfStringResults[count][i]);
if (currentValue > iteration.end || currentValue < iteration.start){
//Co.println("Failed at: " + iteration.start + "," + iteration.end + " / " + currentValue);
count++;
break LABEL_ITERATE_LOOP;
}
iteration.current = currentValue;
i++;
}
count++;
}
return true;
}
public Iteration getIteration(Object request) {
for (Iteration iteration : listOfIteration){
if (iteration.request == request){
return iteration;
}
}
return null;
}
public ArrayList<Iteration> getListOfIterations(){
return listOfIteration;
}
public static class Iteration{
private int start;
private int end;
private int current;
private Object request;
public Iteration(int start, int end, Object request){
this.start = start;
this.end = end;
this.request = request;
}
public double getCurrentValue(){
return this.current;
}
public Object getRequest(){
return this.request;
}
}
}
This of your problem as permuting k numbers from 0 to (n-1), and printing a[n] instead of n. :) That is what you can do, to reduce iterations.
The other way to do it, is to use a number between 0 to n!-1 and figure out what the current permutation is, and print it. Although it is a slower method, it's faster to resume operations in this format - and we can quickly print the kth permutation.
Let us say the numbers are: 1, 2, 3, 4. There are a total of 4! permutation = 24, possible. To print the 15th (counting from zero) permutation, here's what we do:
n = 4
a = 1 2 3 4
divide 15 by (n-1)!
we get 15/6 = 2, reminder = 3.
So the permutation starts with a[2] = 3.
a = 1 2 4
take the reminder, divide by (n-2)!
we get 3/2 = 1, reminder = 1.
so the permutation is now permutation, a[1] = 3, 2
a = 1 4
take the reminder, divide by (n-1)!
we get 1/1 = 1, reminder = 0
so the permutation is now permutation, a[1] = 3, 2, 4.
do until reminder is zero. print a[0]= 3, 2, 4, 1.
^ this is the most efficient way to generate the kth permutation of any series.
You can use BigInteger math to perform this method very efficiently.

How to count possible combination for coin problem

I am trying to implement a coin problem, Problem specification is like this
Create a function to count all possible combination of coins which can be used for given amount.
All possible combinations for given amount=15, coin types=1 6 7
1) 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2) 1,1,1,1,1,1,1,1,1,6,
3) 1,1,1,1,1,1,1,1,7,
4) 1,1,1,6,6,
5) 1,1,6,7,
6) 1,7,7,
function prototype:
int findCombinationsCount(int amount, int coins[])
assume that coin array is sorted. for above example this function should return 6.
Anyone guide me how to implement this??
Use recursion.
int findCombinationsCount(int amount, int coins[]) {
return findCombinationsCount(amount, coins, 0);
}
int findCombinationsCount(int amount, int coins[], int checkFromIndex) {
if (amount == 0)
return 1;
else if (amount < 0 || coins.length == checkFromIndex)
return 0;
else {
int withFirstCoin = findCombinationsCount(amount-coins[checkFromIndex], coins, checkFromIndex);
int withoutFirstCoin = findCombinationsCount(amount, coins, checkFromIndex+1);
return withFirstCoin + withoutFirstCoin;
}
}
You should check this implementation though. I don't have a Java IDE here, and I'm a little rusty, so it may have some errors.
Although recursion can work and is often an assignment to implement in some college level courses on Algorithms & Data Structures, I believe the "dynamic programming" implementation is more efficient.
public static int findCombinationsCount(int sum, int vals[]) {
if (sum < 0) {
return 0;
}
if (vals == null || vals.length == 0) {
return 0;
}
int dp[] = new int[sum + 1];
dp[0] = 1;
for (int i = 0; i < vals.length; ++i) {
for (int j = vals[i]; j <= sum; ++j) {
dp[j] += dp[j - vals[i]];
}
}
return dp[sum];
}
You can use generating function methods to give fast algorithms, which use complex numbers.
Given the coin values c1, c2, .., ck, to get the number of ways to sum n, what you need is the coefficient of x^n in
(1 + x^c1 + x^(2c1) + x^(3c1) + ...)(1+x^c2 + x^(2c2) + x^(3c2) + ...)....(1+x^ck + x^(2ck) + x^(3ck) + ...)
Which is the same as finding the coefficient of x^n in
1/(1-x^c1) * 1/(1-x^c2) * ... * (1-x^ck)
Now using complex numbers, x^a - 1 = (x-w1)(x-w2)...(x-wa) where w1, w2 etc are the complex roots of unity.
So
1/(1-x^c1) * 1/(1-x^c2) * ... * (1-x^ck)
can be written as
1/(x-a1)(x-a2)....(x-am)
which can be rewritten using partial fractions are
A1/(x-a1) + A2/(x-a2) + ... + Am/(x-am)
The coefficient of x^n in this can be easily found:
A1/(a1)^(n+1) + A2/(a2)^(n+1) + ...+ Am/(am)^(n+1).
A computer program should easily be able to find Ai and ai (which could be complex numbers). Of course, this might involve floating point computations.
For large n, this will be probably faster than enumerating all the possible combinations.
Hope that helps.
Very simple with recursion:
def countChange(money: Int, coins: List[Int]): Int = {
def reduce(money: Int, coins: List[Int], accCounter: Int): Int = {
if(money == 0) accCounter + 1
else if(money < 0 || coins.isEmpty) accCounter
else reduce(money - coins.head, coins, accCounter) + reduce(money, coins.tail, accCounter)
}
if(money <= 0 || coins.isEmpty) 0
else reduce(money, coins, 0)
}
This is example in SCALA
Aryabhatta’s answer for
counting the number of ways to make change with coins of fixed
denominations is very cute but also impractical to implement as
described. Rather than use complex numbers, we’ll use modular
arithmetic, similar to how the number-theoretic transform replaces a
Fourier transform for multiplying integer polynomials.
Let D be the least common multiple of the coin denominations. By
Dirichlet’s theorem on arithmetic progressions, there exist infinitely
many prime numbers p such that D divides p - 1. (With any luck,
they’ll even be distributed in a way such that we can find them
efficiently.) We’ll compute the number of ways modulo some p
satisfying this condition. By obtaining a crude bound somehow (e.g.,
n + k - 1 choose k - 1 where n is the total and k is the number
of denominations), repeating this procedure with several different
primes whose product exceeds that bound, and applying the Chinese
remainder theorem, we can recover the exact number.
Test candidates 1 + k*D for integers k > 0 until we find a prime
p. Let g be a primitive root modulo p (generate candidates at
random and apply the standard test). For each denomination d, express
the polynomial x**d - 1 modulo p as a product of factors:
x**d - 1 = product from i=0 to d-1 of (x - g**((p-1)*i/d)) [modulo p].
Note that d divides D divides p-1, so the exponent indeed is an
integer.
Let m be the sum of denominations. Gather all of the constants
g**((p-1)*i/d) as a(0), ..., a(m-1). The next step is to find a
partial fraction decomposition A(0), ..., A(m-1) such that
sign / product from j=0 to m-1 of (a(j) - x) =
sum from j=0 to m-1 of A(j)/(a(j) - x) [modulo p],
where sign is 1 if there are an even number of denominations and
-1 if there are an odd number of denominations. Derive a system of
linear equations for A(j) by evaluating both sides of the given
equation for different values of x, then solve it with Gaussian
elimination. Life gets complicated if there are duplicates; it's probably easiest just to pick another prime.
Given this setup, we can compute the number of ways (modulo p, of
course) to make change amounting to n as
sum from j=0 to m-1 of A(j) * (1/a(j))**(n+1).
The recursive solutions mentioned will work, but they're going to be horrendously slow if you add more coin denominations and/or increase the target value significantly.
What you need to speed it up is to implement a dynamic programming solution. Have a look at the knapsack problem. You can adapt the DP solution mentioned there to solve your problem by keeping a count of the number of ways a total can be reached rather than the minimum number of coins required.
package algorithms;
import java.util.Random;
/**`enter code here`
* Owner : Ghodrat Naderi
* E-Mail: Naderi.ghodrat#gmail.com
* Date : 10/12/12
* Time : 4:50 PM
* IDE : IntelliJ IDEA 11
*/
public class CoinProblem
{
public static void main(String[] args)
{
int[] coins = {1, 3, 5, 10, 20, 50, 100, 200, 500};
int amount = new Random().nextInt(10000);
int coinsCount = 0;
System.out.println("amount = " + amount);
int[] numberOfCoins = findNumberOfCoins(coins, amount);
for (int i = 0; i < numberOfCoins.length; i++)
{
if (numberOfCoins[i] > 0)
{
System.out.println("coins= " + coins[i] + " Count=" + numberOfCoins[i] + "\n");
coinsCount += numberOfCoins[i];
}
}
System.out.println("numberOfCoins = " + coinsCount);
}
private static int[] findNumberOfCoins(int[] coins, int amount)
{
int c = coins.length;
int[] numberOfCoins = new int[coins.length];
while (amount > 0)
{
c--;
if (amount >= coins[c])
{
int quotient = amount / coins[c];
amount = amount - coins[c] * quotient;
numberOfCoins[c] = quotient;
}
}
return numberOfCoins;
}
}
A recursive solution might be the right answer here:
int findCombinationsCount(int amount, int coins[])
{
// I am assuming amount >= 0, coins.length > 0 and all elements of coins > 0.
if (coins.length == 1)
{
return amount % coins[0] == 0 ? 1 : 0;
}
else
{
int total = 0;
int[] subCoins = arrayOfCoinsExceptTheFirstOne(coins);
for (int i = 0 ; i * coins[0] <= amount ; ++i)
{
total += findCombinationsCount(amount - i * coins[0], subCoins);
}
return total;
}
}
Warning: I haven't tested or even compiled the above.
The solution provided by #Jordi is nice but runs extremely slow. You can try input 600 to that solution and see how slow it is.
My idea is to use bottom-up dynamic programming.
Note that generally, the possible combination for money=m and coins{a,b,c} equals combination for
m-c and coins{a,b,c} (with coin c)
combination for m and coins{a,b} (without coin c).
If no coins are available or available coins can not cover the required amount of money, it should fill in 0 to the block accordingly. If the amount of money is 0, it should fill in 1.
public static void main(String[] args){
int[] coins = new int[]{1,2,3,4,5};
int money = 600;
int[][] recorder = new int[money+1][coins.length];
for(int k=0;k<coins.length;k++){
recorder[0][k] = 1;
}
for(int i=1;i<=money;i++){
//System.out.println("working on money="+i);
int with = 0;
int without = 0;
for(int coin_index=0;coin_index<coins.length;coin_index++){
//System.out.println("working on coin until "+coins[coin_index]);
if(i-coins[coin_index]<0){
with = 0;
}else{
with = recorder[i-coins[coin_index]][coin_index];
}
//System.out.println("with="+with);
if(coin_index-1<0){
without = 0;
}else{
without = recorder[i][coin_index-1];
}
//System.out.println("without="+without);
//System.out.println("result="+(without+with));
recorder[i][coin_index] = with+without;
}
}
System.out.print(recorder[money][coins.length-1]);
}
This code is based on the solution provided by JeremyP which is working perfect and I just enhanced it to optimize the performance by using dynamic programming.I couldn't comment on the JeremyP post because I don't have enough reputation :)
public static long makeChange(int[] coins, int money) {
Long[][] resultMap = new Long[coins.length][money+1];
return getChange(coins,money,0,resultMap);
}
public static long getChange(int[] coins, int money, int index,Long[][] resultMap) {
if (index == coins.length -1) // if we are at the end
return money%coins[index]==0? 1:0;
else{
//System.out.printf("Checking index %d and money %d ",index,money);
Long storedResult =resultMap[index][money];
if(storedResult != null)
return storedResult;
long total=0;
for(int coff=0; coff * coins[index] <=money; coff ++){
total += getChange(coins, money - coff*coins[index],index +1,resultMap);
}
resultMap[index][money] = total;
return total;
}
}
First idea:
int combinations = 0;
for (int i = 0; i * 7 <=15; i++) {
for (int j = 0; j * 6 + i * 7 <= 15; j++) {
combinations++;
}
}
(the '<=' is superfluous in this case, but is needed for a more general solution, if you decide to change your parameters)
Below is recursion with memoization java solution. for below one we have 1,2,3,5 as coins and 200 as the target amount.
countCombinations(200,new int[]{5,2,3,1} , 0, 0,new Integer[6][200+5]);
static int countCombinations(Integer targetAmount, int[] V,int currentAmount, int coin, Integer[][] memory){
//Comment below if block if you want to see the perf difference
if(memory[coin][currentAmount] != null){
return memory[coin][currentAmount];
}
if(currentAmount > targetAmount){
memory[coin][currentAmount] = 0;
return 0;
}
if(currentAmount == targetAmount){
return 1;
}
int count = 0;
for(int selectedCoin : V){
if(selectedCoin >= coin){
count += countCombinations(targetAmount, V, currentAmount+selectedCoin, selectedCoin,memory);
}
}
memory[coin][currentAmount] = count;
return count;
}
#include<iostream>
using namespace std;
int solns = 0;
void countComb(int* arr, int low, int high, int Val)
{
bool b = false;
for (size_t i = low; i <= high; i++)
{
if (Val - arr[i] == 0)
{
solns++;
break;
}
else if (Val - arr[i] > 0)
countComb(arr, i, high, Val - arr[i]);
}
}
int main()
{
int coins[] = { 1,2,5 };
int value = 7;
int arrSize = sizeof(coins) / sizeof(int);
countComb(coins,0, arrSize,value);
cout << solns << endl;
return 0;
}
Again using recursion a tested solution, though probably not the most elegant code. (note it returns the number of each coin to use rather than repeating the actual coin ammount n times).
public class CoinPerm {
#Test
public void QuickTest() throws Exception
{
int ammount = 15;
int coins[] = {1,6,7};
ArrayList<solution> solutionList = SolvePerms(ammount, coins);
for (solution sol : solutionList)
{
System.out.println(sol);
}
assertTrue("Wrong number of solutions " + solutionList.size(),solutionList.size() == 6);
}
public ArrayList<solution> SolvePerms(int ammount, int coins[]) throws Exception
{
ArrayList<solution> solutionList = new ArrayList<solution>();
ArrayList<Integer> emptyList = new ArrayList<Integer>();
solution CurrentSolution = new solution(emptyList);
GetPerms(ammount, coins, CurrentSolution, solutionList);
return solutionList;
}
private void GetPerms(int ammount, int coins[], solution CurrentSolution, ArrayList<solution> mSolutions) throws Exception
{
int currentCoin = coins[0];
if (currentCoin <= 0)
{
throw new Exception("Cant cope with negative or zero ammounts");
}
if (coins.length == 1)
{
if (ammount % currentCoin == 0)
{
CurrentSolution.add(ammount/currentCoin);
mSolutions.add(CurrentSolution);
}
return;
}
// work out list with one less coin.
int coinsDepth = coins.length;
int reducedCoins[] = new int[(coinsDepth -1 )];
for (int j = 0; j < coinsDepth - 1;j++)
{
reducedCoins[j] = coins[j+1];
}
// integer rounding okay;
int numberOfPerms = ammount / currentCoin;
for (int j = 0; j <= numberOfPerms; j++)
{
solution newSolution = CurrentSolution.clone();
newSolution.add(j);
GetPerms(ammount - j * currentCoin,reducedCoins, newSolution, mSolutions );
}
}
private class solution
{
ArrayList<Integer> mNumberOfCoins;
solution(ArrayList<Integer> anumberOfCoins)
{
mNumberOfCoins = anumberOfCoins;
}
#Override
public String toString() {
if (mNumberOfCoins != null && mNumberOfCoins.size() > 0)
{
String retval = mNumberOfCoins.get(0).toString();
for (int i = 1; i< mNumberOfCoins.size();i++)
{
retval += ","+mNumberOfCoins.get(i).toString();
}
return retval;
}
else
{
return "";
}
}
#Override
protected solution clone()
{
return new solution((ArrayList<Integer>) mNumberOfCoins.clone());
}
public void add(int i) {
mNumberOfCoins.add(i);
}
}
}
Dynamic Programming Solution
Given an array of denominations D = {d1, d2, d3, ... , dm} and a target amount W. Note that D doesn't need to be sorted.
Let T(i, j) be the number of combinations that make up amount j using only denominations on the left of the ith one (can include itself) in D.
We have:
T(0, 0) = 1 : since the amount is 0, there is only 1 valid combination that makes up 0, which is the empty set.
T(i, j) = T(i - 1, j) if D[i] > j
T(i, j) = T(i - 1, j) + T(i, j - D[i]) if D[i] <= j
public int change(int amount, int[] coins) {
int m = coins.length;
int n = amount;
int[][] dp = new int[m + 1][n + 1];
dp[0][0] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (j < coins[i - 1]) {
dp[i][j] = dp[i - 1][j];
}
else {
dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]];
}
}
}
return dp[m][n];
}
public static void main(String[] args) {
int b,c,total = 15;
int combos =1;
for(int d=0;d<total/7;d++)
{
b = total - d * 7;
for (int n = 0; n <= b /6; n++)
{
combos++;
}
}
System.out.print("TOTAL COMBINATIONS = "+combos);
}
Below is a recursive backtracking solution I created, It lists and counts all possible combination of denominations (coins) that would add up to a given amount.
Both denominations and the amounts can be dynamic
public class CoinComboGenerate {
public static final int[] DENO = {1,6,7};
public static final int AMOUNT = 15;
public static int count = 0;
public static void change(int amount) {
change(amount, new ArrayList<>(),0);
}
private static void change(int rem, List<Integer> coins, int pos) {
if (rem == 0) {
count++;
System.out.println(count+")"+coins);
return;
}
while(pos<DENO.length){
if (rem >= DENO[pos]) {
coins.add(DENO[pos]);
change(rem - DENO[pos], coins,pos);
coins.remove(coins.size() - 1); //backtrack
}
pos++;
}
}
public static void main(String[] args) {
change(AMOUNT);
}
}
Output:
1)[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
2)[1, 1, 1, 1, 1, 1, 1, 1, 1, 6]
3)[1, 1, 1, 1, 1, 1, 1, 1, 7]
4)[1, 1, 1, 6, 6]
5)[1, 1, 6, 7]
6)[1, 7, 7]
The same problem for coins(1,5,10,25,50) has one of below solutions.
The solution should satisfy below equation:
1*a + 5*b + 10*c + 25*d + 50*e == cents
public static void countWaysToProduceGivenAmountOfMoney(int cents) {
for(int a = 0;a<=cents;a++){
for(int b = 0;b<=cents/5;b++){
for(int c = 0;c<=cents/10;c++){
for(int d = 0;d<=cents/25;d++){
for(int e = 0;e<=cents/50;e++){
if(1*a + 5*b + 10*c + 25*d + 50*e == cents){
System.out.println("1 cents :"+a+", 5 cents:"+b+", 10 cents:"+c);
}
}
}
}
}
}
}
This can be modified for any general solutions.

Categories

Resources