Решение этой проблемы было дано миллион раз в Интернете. Задача называется Проблема смены монет . Решения можно найти в http://rosettacode.org/wiki/Count_the_coins, а математическую модель - в http://jaqm.ro/issues/volume-5,issue-2/pdfs/patterson_harmel.pdf (или в Google проблема замены монет ).
Кстати, решение Scala от Tsagadai интересно. В этом примере выводится либо 1, либо 0. В качестве побочного эффекта в консоли отображаются все возможные решения. Он отображает решение, но никак не может его использовать.
Чтобы быть максимально полезным, код должен возвращать List[List[Int]]
, чтобы можно было получить номер решения (длина списка списков), «лучшее» решение (самый короткий список) или все возможные решения.
Вот пример. Это очень неэффективно, но легко понять.
object Sum extends App {
def sumCombinations(total: Int, numbers: List[Int]): List[List[Int]] = {
def add(x: (Int, List[List[Int]]), y: (Int, List[List[Int]])): (Int, List[List[Int]]) = {
(x._1 + y._1, x._2 ::: y._2)
}
def sumCombinations(resultAcc: List[List[Int]], sumAcc: List[Int], total: Int, numbers: List[Int]): (Int, List[List[Int]]) = {
if (numbers.isEmpty || total < 0) {
(0, resultAcc)
} else if (total == 0) {
(1, sumAcc :: resultAcc)
} else {
add(sumCombinations(resultAcc, sumAcc, total, numbers.tail), sumCombinations(resultAcc, numbers.head :: sumAcc, total - numbers.head, numbers))
}
}
sumCombinations(Nil, Nil, total, numbers.sortWith(_ > _))._2
}
println(sumCombinations(15, List(1, 2, 5, 10)) mkString "\n")
}
При запуске отображается:
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2)
List(1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2)
List(1, 1, 1, 1, 1, 2, 2, 2, 2, 2)
List(1, 1, 1, 2, 2, 2, 2, 2, 2)
List(1, 2, 2, 2, 2, 2, 2, 2)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5)
List(1, 1, 1, 1, 1, 1, 1, 1, 2, 5)
List(1, 1, 1, 1, 1, 1, 2, 2, 5)
List(1, 1, 1, 1, 2, 2, 2, 5)
List(1, 1, 2, 2, 2, 2, 5)
List(2, 2, 2, 2, 2, 5)
List(1, 1, 1, 1, 1, 5, 5)
List(1, 1, 1, 2, 5, 5)
List(1, 2, 2, 5, 5)
List(5, 5, 5)
List(1, 1, 1, 1, 1, 10)
List(1, 1, 1, 2, 10)
List(1, 2, 2, 10)
List(5, 10)
Функция sumCombinations()
может использоваться сама по себе, и результат может быть дополнительно проанализирован для отображения «наилучшего» решения (самый короткий список) или количества решений (количество списков).
Обратите внимание, что даже в этом случае требования могут быть не полностью выполнены. Может случиться так, что порядок каждого списка в решении будет значительным. В таком случае каждый список должен дублироваться столько раз, сколько существует комбинация его элементов. Или нас могут интересовать только разные комбинации.
Например, мы можем считать, что List(5, 10)
должно давать две комбинации: List(5, 10)
и List(10, 5)
. Для List(5, 5, 5)
это может дать три комбинации или только одну, в зависимости от требований. Для целых чисел три перестановки эквивалентны, но если мы имеем дело с монетами, как в «проблеме смены монет», они не являются.
В требованиях также не указан вопрос о том, можно ли использовать каждый номер (или монету) только один или несколько раз. Мы могли бы (и мы должны!) Обобщить проблему в список списков вхождений каждого числа. В реальной жизни это переводится как «как можно заработать определенную сумму денег с помощью набора монет (а не набора ценностей монет)». Первоначальная проблема - это только частный случай этой проблемы, когда у нас есть столько экземпляров каждой монеты, сколько необходимо, чтобы получить общую сумму для каждой монеты достоинством.