БлогNot. PHP: считаем числа Армстронга

PHP: считаем числа Армстронга

Что такое числа Армстронга, легко прочитать в Вики.

Придумать дельный алгоритм, не сводящийся к перебору, видимо, сложнее. Идея такого алгоритма есть вот здесь.

Если таки перебирать, да ещё и на заведомо медленном PHP, то видимых оптимизаций немного. Можно основной алгоритм оформить как цикл по разрядности числа, в котором вызывается функция check(), проверяющая условия Армстронга для всех чисел заданной разрядности.

Все однозначные числа являются числами Армстронга, для них отдельная проверка не нужна. Число известной разрядности $n можно преобразовать в массив цифр посредством функции sscanf с шаблоном "%1d%1d...%1d", где %1d повторено $n раз. Операцию возведения цифры в степень можно затабулировать, а не вычислять трудоёмкими функциями над вещественными числами.

У меня получилось время выполнения скрипта не более, чем над 4-значными числами ~1 сек., над 5-значными около 4 сек., над 6-значными уже примерно 45 сек. Дальше, конечно, будет экспоненциальный рост времени работы скрипта.

Ниже приводится полный листинг, поменяйте значение D в начале и смотрите вывод сами :)

<?php
 set_time_limit (3600);
 define("D", 5); // максимальное количество цифр числа

 function array_prod (&$array_a, $array_b) {
  // Перемножение массивов поэлементно
  $array_a = array_map (function($a,$b) {return $a*$b;}, $array_a, $array_b);
 }

 // Вернёт массив из n-значных чисел Армстронга
 function check ($n, $deg10, $degree){
  $result = array();
  $format = str_repeat ("%1d", $n);
  for ($k = $deg10[$n-1]; $k < $deg10[$n]-1; $k++) {
   $digits = sscanf($k, $format); //массив цифр числа
   $sum = 0;
   array_walk ($digits, function($d) use(&$sum, $degree) {
    $sum += $degree[$d];
   });
   if($sum == $k) $result[] = $k; 
  }
  return $result;
 }

 $time_start = microtime(true);
 $mult = 1;
 $deg10 = array(); 
 $deg10[] = $mult;
 for ($i=1; $i <= D; $i++) $deg10[] = ($mult *= 10);
 $digits = range(0,9);
 $degree = $digits;
 $armstrong[1] = $digits;
 for ($n = 2; $n <= D; $n++) {
  array_prod ($degree, $digits);
  $armstrong[] = check ($n, $deg10, $degree);
 }
 $time = microtime(true) - $time_start;
 print ('<br>Числа Армстронга:<pre>');
 var_dump ($armstrong);
 printf ("</pre><br>Время счёта = %.2f c", $time);
?>

07.03.2017, 23:30 [4583 просмотра]


теги: php числа алгоритм

показать комментарии (1)