fork download
  1. <?php
  2. /* Этот алгоритм начинает перебор с ближайшего к сумме значения, поэтому он найдет комбинацию быстрее. Каждую итерацию
  3. высчитывается максимальное количество купюр следущего номинала, то есть мы не не перебираем купюры, заведомо превышающие сумму.*/
  4.  
  5. declare(strict_types=1);
  6.  
  7. $money = 6600;
  8.  
  9. $bills = array( // Купюры по условию. Номинал купюры => количество купюр этого номинала
  10. 5000 => 1,
  11. 2000 => 4,
  12. 500 => 1,
  13. 200 => 3
  14. );
  15.  
  16. $i=0;
  17. foreach ($bills as $denomination => $amount) {
  18. $denominationOfBills[$i] = $denomination;
  19. $numberOfBills[$i] = range(0, $amount);
  20. $i+=1;
  21. }
  22.  
  23. # Вышестоящим циклом создаются следующие массивы, которые до этого писались вручную.
  24. /*$denominationOfBills = [ // Массив всех номиналов купюр
  25.   0 => 5000,
  26.   1 => 2000,
  27.   2 => 500,
  28.   3 => 200
  29. ];
  30.  
  31. $numberOfBills = [ // Количество купюр всех номиналов
  32.   0 => range(0, 1),
  33.   1 => range(0, 4),
  34.   2 => range(0, 1),
  35.   3 => range(0, 3)
  36. ]; */
  37.  
  38. function generateCombinations( array $numberOfBills, int $money, array $denominationOfBills, array $combination = [], $N = 0)
  39. {
  40.  
  41. # Высчитывается максимальное значение количества купюр перебираемого номинала, чтобы не превысить требуемую сумму
  42. if ($N < 4) { /* Если не поставить это условие, то будет пробовать высчитываться следующее после последнего(несуществующее) лимитное значение */
  43. $nextMaxLimit = floor(($money - sum($combination, $denominationOfBills)) / $denominationOfBills[$N]);
  44. if ($nextMaxLimit > max($numberOfBills[$N])) {
  45. $nextMaxLimit = max($numberOfBills[$N]);
  46. }
  47. $numberOfBills[$N] = range($nextMaxLimit, 0);
  48. }
  49.  
  50. if (count($combination) == count($denominationOfBills)) { // Когда кол-во элементов комбинации == кол-ву предоставленных номиналов
  51. yield $combination; // Возвращаем комбинацию
  52. } else {
  53. foreach ($numberOfBills[$N] as $valueOnSquare) {
  54. yield from generateCombinations($numberOfBills, $money, $denominationOfBills, array_merge($combination, [$valueOnSquare]), $N + 1);
  55. }
  56. }
  57. }
  58.  
  59. function sum(array $combination, array $denominationOfBills) : float // Функция высчитывающая сумму любой комбинации
  60. {
  61. $sum = 0;
  62. $i = 0;
  63. foreach ($combination as $amount) {
  64. $sum += $amount * $denominationOfBills[$i];
  65. $i += 1;
  66. }
  67. return $sum;
  68. }
  69.  
  70. $combinationGenerator = generateCombinations($numberOfBills, $money, $denominationOfBills);
  71. foreach ($combinationGenerator as $combination) {
  72. if (sum($combination, $denominationOfBills) == $money) {
  73. echo "Комбинация с наименьшим кол-вом купюр надейна !" . PHP_EOL;
  74. print_r($combination);
  75. break;
  76. }
  77. //print_r($combination);
  78.  
  79. }
  80. # Вывод в требуемом формате
  81. for ($i = 0; $i < count($combination); $i++) {
  82. echo "{$denominationOfBills[$i]}x{$combination[$i]} ";
  83. }
Success #stdin #stdout 0.02s 24416KB
stdin
Standard input is empty
stdout
Комбинация с наименьшим кол-вом купюр надейна !
Array
(
    [0] => 0
    [1] => 3
    [2] => 0
    [3] => 3
)
5000x0 2000x3 500x0 200x3