A weekly algorithmic problem: change change change

Posted by jdc44 on Thu, 08 Aug 2019 14:10:37 +0200

Questions:

Known convertible change types are 1 yuan, 5 yuan, 10 yuan, 20 yuan 4 kinds, now there are 100 yuan to change into change and the total amount is less than 15 pieces, how many kinds of exchange? What are the differences?

Ideas:

Known as a n optional data set S, such as [1, 5, 10, 20], we now need to extract n numbers from it, the tensor of each number is a, so that a1xn1+a2xn2+...aixni = 100.

The maximum denomination is 20, a total of 100/20 = 5 sheets, which is the minimum number of sheets, so the lower limit of the cycle is 5, and the upper limit is 15.

That is to say, from the S data set, take 5-15 numbers, so that their sum is 100, the number can be repeated.

Consider the simplest case first. No consideration is given to the sum limit of 100. Just take five numbers from data set S, and the numbers can be repeated. How many kinds of situations are there?

In our problem, there is no requirement for the order of the number taken out. For example, there is no difference between [1, 20, 10, 5, 5] and [1, 5, 5, 10, 20], so this is a combinatorial problem.
But the general combinatorial problem is to select n from m different numbers, the formula is C(m,n).
But the numbers here are allowed to be repeated. What should we do? If we take the five numbers [1,1,1,1,1] (i.e. n=5), we can keep the first one unchanged. The remaining four numbers (i.e. n-1) are all added with a random number of more than 100, so that they are different from other elements in S. That would be equivalent to taking n numbers out of different numbers from m+n-1. The formula is C (m+n-1, n-1). ) Verify it.

If S is [1,5], two combinations can be obtained as follows:
[1,1], [1,5], [5,5], a total of three.
Using the formula, C (2 + 2 - 1, 2) = C (3, 2) = 3; correct.
If we take three of them, we can get the following combinations:
[1,1,1], [5,1,1], [5,5,1], [5,5,5], a total of four species.
Calculated by formula, C(2+3-1,3)=4; correct.

So the number of combinations of N repeatable numbers from m different numbers is C(m+n-1,n)

Now to list these combinations, we can do the following:
We set up a temporary array to store the subscripts of the elements in S.
Initialized as [0, 0, 0, 0, 0], indicating that all five elements taken are S[0];
Then add 1 to the first place and change it to [1,0,0,0,0]. The amount expressed is [5,1,1,1,1];
Priority continues to accumulate until all S is compiled, and eventually becomes [3,0,0,0];

This is the first round of the process, namely:
[0,0,0,0,0]
[1,0,0,0,0]
[2,0,0,0,0]
[3,0,0,0,0]

Then, in the next round, when the subscript of the first element exceeds 3, the second element is processed as follows:
[1,1,0,0,0]
Then continue to accumulate the first place.
[2,1,0,0,0]
[3,1,0,0,0]

When the first place exceeds 3, the second place is added up.
[1,2,0,0,0]
Take the lead and continue to accumulate the first place
[2,2,0,0,0]
[3,2,0,0,0]

Repeat this process until all elements become
[3,3,3,3,3]

But all three conditions are not good to judge, we can add one more place to the subscript array, so that when the sixth element has value, that is to say, it is over.
That is, when the element subscript becomes [1,1,1,1,1,1], the program exits.

The final result is to aggregate all subscript arrays and map them to the corresponding elements of the data set.

Answer:

php

/**
 * Repeatable combinations of elements
 * @param $arr array Optional element array
 * @param $n int Quantity to be taken
 * @return array
 */
function repeatedCombination($arr, $n)
{
    $len = count($arr);// Array length
    $tmp = array_fill(0, $n + 1, 0);// Subscripts for storing composite elements, initial 0
    $len--; // Array length minus 1
    $result = array();
    while (1) {
        for ($i = 0; $i < $n; ++$i) { // n elements
            if ($tmp[$i] > $len) {
                $tmp[$i + 1] += 1;
                for ($j = $i; $j >= 0; --$j) {
                    $tmp[$j] = $tmp[$j + 1];
                }
            }
        }

        // When the last bit is not zero, all combinations have been processed and exited.
        if ($tmp[$n] > 0) {
            break;
        }

        $item = array();
        for ($i = 0; $i < $n; $i++) {
            $item[] = $arr[$tmp[$i]];
        }
        $result[] = $item;
        $tmp[0] += 1;
    }
    return $result;
}

$arr = array("1", "5", "10", "20");

$m = array();
for ($i = 5; $i < 15; $i++) {
    $rs = repeatedCombination($arr, $i);
    foreach ($rs as $r) {
        if (array_sum($r) == 100) {
            $m[] = $r;
        }
    }
}
print_r($m);

Output:

Array
(
    [0] => 20-20-20-20-20
    [1] => 20-20-20-20-10-10
    [2] => 20-20-20-20-10-5-5
    [3] => 20-20-20-10-10-10-10
    [4] => 20-20-20-20-5-5-5-5
    [5] => 20-20-20-10-10-10-5-5
    [6] => 20-20-10-10-10-10-10-10
    [7] => 20-20-20-10-10-5-5-5-5
    [8] => 20-20-10-10-10-10-10-5-5
    [9] => 20-10-10-10-10-10-10-10-10
    [10] => 20-20-20-10-5-5-5-5-5-5
    [11] => 20-20-10-10-10-10-5-5-5-5
    [12] => 20-10-10-10-10-10-10-10-5-5
    [13] => 10-10-10-10-10-10-10-10-10-10
    [14] => 20-20-20-20-10-5-1-1-1-1-1
    [15] => 20-20-20-5-5-5-5-5-5-5-5
    [16] => 20-20-10-10-10-5-5-5-5-5-5
    [17] => 20-10-10-10-10-10-10-5-5-5-5
    [18] => 10-10-10-10-10-10-10-10-10-5-5
    [19] => 20-20-20-20-5-5-5-1-1-1-1-1
    [20] => 20-20-20-10-10-10-5-1-1-1-1-1
    [21] => 20-20-10-10-5-5-5-5-5-5-5-5
    [22] => 20-10-10-10-10-10-5-5-5-5-5-5
    [23] => 10-10-10-10-10-10-10-10-5-5-5-5
    [24] => 20-20-20-10-10-5-5-5-1-1-1-1-1
    [25] => 20-20-10-10-10-10-10-5-1-1-1-1-1
    [26] => 20-20-10-5-5-5-5-5-5-5-5-5-5
    [27] => 20-10-10-10-10-5-5-5-5-5-5-5-5
    [28] => 10-10-10-10-10-10-10-5-5-5-5-5-5
    [29] => 20-20-20-10-5-5-5-5-5-1-1-1-1-1
    [30] => 20-20-10-10-10-10-5-5-5-1-1-1-1-1
    [31] => 20-10-10-10-10-10-10-10-5-1-1-1-1-1
    [32] => 20-20-5-5-5-5-5-5-5-5-5-5-5-5
    [33] => 20-10-10-10-5-5-5-5-5-5-5-5-5-5
    [34] => 10-10-10-10-10-10-5-5-5-5-5-5-5-5
)

golang:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    data := []string{"1", "5", "10", "20"}
    m := make([][]string, 0)
    for i := 5; i < 15; i++ {
        rs := repeatedCombination(data, i)
        for _, r := range rs {
            sum := 0
            for _, v := range r {
                val, _ := strconv.Atoi(v)
                sum += val
            }
            if sum == 100 {
                m = append(m, r)
            }
        }
    }
    fmt.Println(m)
}

func repeatedCombination(data []string, n int) [][]string {
    length := len(data)
    limit := length - 1
    tmp := make([]int, n+1)
    result := make([][]string, 0)
    for {
        for i := 0; i < n; i++ {
            if tmp[i] > limit {
                tmp[i+1] += 1
                for j := i; j >= 0; j-- {
                    tmp[j] = tmp[j+1]
                }
            }
        }

        if tmp[n] > 0 {
            break
        }

        var item []string
        for i := 0; i < n; i++ {
            item = append(item, data[tmp[i]])
        }
        result = append(result, item)

        tmp[0] += 1
    }
    return result
}

Output:

[[20 20 20 20 20]
[20 20 20 20 10 10] 
[20 20 20 20 10 5 5]
[20 20 20 10 10 10 10]
[20 20 20 20 5 5 5 5] 
[20 20 20 10 10 10 5 5]
[20 20 10 10 10 10 10 10] 
[20 20 20 10 10 5 5 5 5] 
[20 20 10 10 10 10 10 5 5]
[20 10 10 10 10 10 10 10 10] 
[20 20 20 10 5 5 5 5 5 5]
[20 20 10 10 10 10 5 5 5 5]
[20 10 10 10 10 10 10 10 5 5] 
[10 10 10 10 10 10 10 10 10 10]
[20 20 20 20 10 5 1 1 1 1 1] 
[20 20 20 5 5 5 5 5 5 5 5] 
[20 20 10 10 10 5 5 5 5 5 5] 
[20 10 10 10 10 10 10 5 5 5 5] 
[10 10 10 10 10 10 10 10 10 5 5] 
[20 20 20 20 5 5 5 1 1 1 1 1] 
[20 20 20 10 10 10 5 1 1 1 1 1] 
[20 20 10 10 5 5 5 5 5 5 5 5]
[20 10 10 10 10 10 5 5 5 5 5 5] 
[10 10 10 10 10 10 10 10 5 5 5 5] 
[20 20 20 10 10 5 5 5 1 1 1 1 1]
[20 20 10 10 10 10 10 5 1 1 1 1 1] 
[20 20 10 5 5 5 5 5 5 5 5 5 5] 
[20 10 10 10 10 5 5 5 5 5 5 5 5] 
[10 10 10 10 10 10 10 5 5 5 5 5 5]
[20 20 20 10 5 5 5 5 5 1 1 1 1 1]
[20 20 10 10 10 10 5 5 5 1 1 1 1 1]
[20 10 10 10 10 10 10 10 5 1 1 1 1 1] 
[20 20 5 5 5 5 5 5 5 5 5 5 5 5] 
[20 10 10 10 5 5 5 5 5 5 5 5 5 5]
[10 10 10 10 10 10 5 5 5 5 5 5 5 5]]

Topics: Go less PHP