fork(1) download
  1. <?php
  2.  
  3.  
  4. //требуемая сумма
  5. $amount = 6600;
  6.  
  7. //запас наличных
  8. $nominals = array(100, 200, 500, 1000, 2000, 5000);
  9. $check = array();
  10. $check[0] = array(
  11. 100 => 0,
  12. 200 => 3,
  13. 500 => 1,
  14. 1000 => 0,
  15. 2000 => 4,
  16. 5000 => 1
  17. );
  18.  
  19. /* Алгоритм начинает свою работу с того что массив $solutionsStorage заполняется значением 9999
  20. значение 9999 в данном случае аналог false. Ключ в данном массиве - число, для которого ищется лучшее (меньшее) количество банкнот, которым можно выдать это число.
  21. Значение массива $solutionsStorage под ключём n - лучшее(меньшее) количество банкнот, которым можно выдать число n.
  22. Значению $solutionsStorage с ключём 0 присваиваится целочисленное значение 0, так как сумму 0р можно выдать количеством 0 банкнот.
  23.  
  24. Далее цикл перебирает массив $solutionsStorage, и для каждого ключа(и каждого значения $amount до 6600 соответственно) находит лучшее(меньшее количество банкнот) алгоритмом описанным ниже.
  25. Если же определённую сумму выдать нельзя, то у ключа равного этой сумме значение будет 9999 - то есть false.
  26. Чтобы лучше понять как действует алгоритм рассмотрим его работу поэтапно на примере суммы 100 р и 500р.
  27.  
  28. $k = 100 (рассматривается ситуация, когда в банкомате есть купюра в 100р, в рабочем примере этой купюры в банкомате нет)
  29. строка 75: банкнота номиналом 100(все остальные банкноты не проходят первую проверку в строке 76)
  30. строка 76: $solutionsStorage[100 - 100] < $solutionsStorage[100](тут будет число 9999 в первом проходе цикла)
  31. вторая проверка в строке 76 нужна для двух целей. Первая цель - определить что данную сумму вообще возможно выдать
  32. имеющимися номиналами (если нельзя, то $solutionsStorage[$k - $nominals[$i]] будет больше или равно $solutionsStorage[$k]
  33. Вторая цель - определить минимальное количество банкнот, которым можно выдать сумму(более подробно будет рассмотренно
  34. в примере с суммой в 500р))
  35. строка 76: третья проверка определяет есть ли нужная купюра номиналом $i в банкомате
  36. строка 77: если все три проверки успешны, значению $solutionsStorage[100] присваивается значение $solutionsStorage[0]
  37. строка 78: также значению $check[100] присваивается массив с количеством доступных банкнот, который находится в $check[0]
  38. строка 79: также в переменную $bestNominal записывается номинал банкноты - 100, также переменная $tic становится true
  39. далее, если все три проверки пройдены, и найден лучший номинал для суммы $k мы отнимаем 1 банкноту номинала $bestNominal
  40. из массива с количеством доступных банкнот(строка 85), добавляем одну банкноту к истинному решению в массив $solutionsStorage с ключем 100 (строка 86)
  41. таким образом значение $solutionsStorage[100] становится 1, и в заключении задаем переменной $tic значение false\
  42.  
  43. $k = 500 (рассматривается ситуация, когда в банкомате есть купюра в 100р, в рабочем примере этой купюры в банкомате нет)
  44. Первая итерация вложенного цикла{
  45. В этот раз я не буду акцентировать внимание на первой проверке, сразу перейдём ко второй
  46. строка 75: банкнота номиналом 100р
  47. строка 76: $solutionsStorage[500 - 100](под этим ключем будет значение 2 банкноты, высчитанное ранее, 2 меньше чем 9999)
  48. строка 76: купюра с номиналом $nominals[$i] , то есть 100 в массиве с количеством доступных банкнот у нас тоже есть, значит третью проверку мы проходим
  49. далее присваиваем $solutionsStorage[500] значение 2 (купюры), прибавляем к этому значению 1, и вычитаем одну купюру этого номинала из
  50. банкомата, массив который представляет это теперь находится в $check[500]
  51. }
  52. Вторая итерация вложенного цикла{
  53. строка 75: банкнота номиналом 200р
  54. строка 76: $solutionsStorage[500 - 200](под этим ключем будет значение 2 банкноты, высчитанное ранее, 2 меньше чем 3, вторая проверка пройдена)
  55. Дальше идут примерно те же действия что и в первой итерации, с небольшими различиями (так, например значение $check[500] заполняется значением $check[300]
  56. вместо $check[400], и уже оттуда вычитается одна банкнота номиналом 200р)
  57. }
  58. Третья итерация вложенного цикла{
  59. строка 75: банкнота номиналом 500р
  60. строка 76: $solutionsStorage[500 - 500](под этим ключем будет значение 0 банкноты, высчитанное ранее, 0 меньше чем 3, вторая проверка пройдена)
  61. После выполняются те же действия что и в итерациях выше с небольшими различиями.
  62. }
  63. В итоге в $solutionsStorage[500] значение 1 (одна банкнота), а из $check[500] будет вычтена 1 банкнота номиналом 500р
  64. */
  65.  
  66. $tic = false; //переменная, которая позволяет или запрещает добавить одну банкноту к истинному решению, в зависимости от истинности выражения в строке
  67. $bestNominal = 0;
  68. $solutionsStorage = array();
  69. $solutionsStorage = array_fill(0, $amount + 1, 9999); // заполнение массива значением 9999, до $amount
  70. $solutionsStorage[0] = 0;
  71. for ($k = 1; $k < $amount + 1; $k++){
  72. for ($i = 0; $i < count($nominals); $i++){
  73. if ($k - $nominals[$i] >= 0 && $solutionsStorage[$k - $nominals[$i]] < $solutionsStorage[$k] && $check[$k - $nominals[$i]][$nominals[$i]] > 0){
  74. $solutionsStorage[$k] = $solutionsStorage[$k - $nominals[$i]];
  75. $check[$k] = $check[$k - $nominals[$i]]; //присвоение массиву в значении $k массива ($k - номинал банкноты)
  76. $bestNominal = $nominals[$i];
  77. $tic = true;
  78. }
  79.  
  80. }
  81. if($tic == true){ //прибавление банкноты к истинному решению, вычитание банкноты из банкомата
  82. $check[$k][$bestNominal] -= 1;
  83. $solutionsStorage[$k] += 1;
  84. $tic = false;
  85. }
  86. }
  87.  
  88. if ($solutionsStorage[$amount] >= 9999){
  89. echo 'выдать сумму невозможно';
  90. }
  91. else{
  92. if ($solutionsStorage[$amount] == 0){
  93. 'выдано ноль банкнот';
  94. }
  95. else{
  96. echo "Сумма к выдаче:{$amount}\n";
  97. echo "выдано банкнот всего: {$solutionsStorage[$amount]}\n";
  98. for($p = count($nominals) - 1; $p >= 0; $p--){
  99. $bankn = $check[0][$nominals[$p]] - $check[$amount][$nominals[$p]];
  100. echo "выдано {$bankn} банкнот номиналом {$nominals[$p]} рублей\n";
  101. }
  102. }
  103. }
Success #stdin #stdout 0.02s 52488KB
stdin
Standard input is empty
stdout
Сумма к выдаче:6600
выдано банкнот всего: 6
выдано 0 банкнот номиналом 5000 рублей
выдано 3 банкнот номиналом 2000 рублей
выдано 0 банкнот номиналом 1000 рублей
выдано 0 банкнот номиналом 500 рублей
выдано 3 банкнот номиналом 200 рублей
выдано 0 банкнот номиналом 100 рублей