Показать сообщение отдельно
Старый 16.03.2005, 17:51     # 103
Ghost
::VIP::
Звезда первого сезона
Молчун-2004
 
Аватар для Ghost
 
Регистрация: 24.08.2002
Сообщения: 1 575

Ghost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех ГуруGhost Отец (мать) всех Гуру
Гыхм... Я уже ухожу сегодня, появлюсь теперь не знаю когда. Так что выкладываю свое решение. В процессе решения мне на ум приходили оба предложенных решения (и еще парочка), но первое я сразу отмел из-за наличия перебора, второе - не сумел довести до ума, не хватило терпения (или соображалки).

Может мои рассуждения вам покажутся чересчур сложными, но решал задачу я именно так (на подобные выкладки меня натолкнули воспоминания о прочитанном от корки до корки "Искусстве программирования" Кнута).

Итак. Для начала строим дерево следующего вида: корень (уровень №0) - некий пустой элемент, из него выходят девять ветвей к узлам 1, 2, ..., 8, 9 - уровень №1; из каждого эелемента 1-го уровня также выходят ветви т.о., чтобы путь к ним по узлам (цифрам в узлах) не содержал повторяющихся цифирей, например, из узла (1) 1-го уровня выходят ветви к узлам 0, 2, 3, ..., 8, 9. И т.д. - всего 10 уровней, что очевидно - не может существовать десятичное число с неповторяющимися цифрами длиной более 10. Т.о., при проходе сверху-вниз по этому дереву всегда получается "разноциферное" число.

Само это дерево в программе не потребуется, и строить его не нужно будет. Важны некоторые характеристики уровней. А именно:
  1. T - количество ветвей, спускающихся в текущий уровень из любого элемента предыдущего уровня. Т.е., фактически, какое количество цифр можно добавить к уже существующему "разноциферному" числу, не нарушая его. Это число легко определяется следующим образом:
    T[1] = 9;
    T[i] = 11 - i, 1<i<=10.
  2. F - общее число узлов в уровне, т.е., в приложении к данной задаче, - количество 1-, 2-, 3-значных "разноциферных" чисел и т.д. Это число тоже легко вычисляется:
    F[1] = T[1];
    F[i] = T[i] x F[i - 1], 1<i<=10.
  3. S - общее число узлов в дереве по текущий уровень включительно или, другими словами, количество "разноциферных" чисел длины не более 2, 3, и т.д.:
    S[1] = F[1];
    S[i] = F[i] + S[i - 1], 1<i<=10.
Все эти числа легко найти и занести в массивы. Можно, конечно, составить специальные функции для вычисления каждого числа, но проще посчитать один раз и потом результаты хранить и использовать - благо дело места требуется немного. Да и сама программа сокращется.

Далее, зная N (номер искомого числа), легко вычисляется K - количество разрядов в нем: сперва записываем в K единицу, а потом увеличиваем, пока S[K] < N.

После этого я запоминал номера узлов каждого уровня (начиная с K-го и вверх), через которые нужно пройти, чтобы получить искомое. В результате получил массив A из K элементов.

Теперь, зная номера узлов в каждом уровне, легко определить путь прохода дерева с одновременным формированием числа. Для этого я просматривал массив A в прямом порядке (от 1 до K) и находил номера цифр ((A[i] - 1) mod T[i]) из строки W (в начале, перед первым шагом = '123456789'), добавляя их к результирующей строке Z и удаляя из W.

На первый взгляд все кажется громоздким, но на деле выходит достаточно коротенькая программка:
Код:
uses
  crt;

var
  i, k, n:    longint;
  a, t, f, s: array [1..10] of longint;
  w, z:       string;

begin
  clrscr;
  write('n = '); readln(n);
  if (n > 9) then begin
    fillchar(t, sizeof(t), 0); t[1] := 9;
    fillchar(f, sizeof(f), 0); f[1] := t[1];
    fillchar(s, sizeof(s), 0); s[1] := f[1];
    for i := 2 to 10 do begin
      t[i] := 11 - i;
      f[i] := t[i] * f[pred(i)];
      s[i] := f[i] + s[pred(i)];
    end;
    if n > s[10] then z := 'no solutions' else begin
      k := 1;
      while s[k] < n do inc(k);
      fillchar(a, sizeof(a), 0);
      for i := k downto 1 do begin
        if i = k then a[i] := n - s[i - 1]
                 else a[i] := succ(pred(a[i + 1]) div t[i + 1]);
      end;
      w := '123456789';
      z := '';
      for i := 1 to k do begin
        z := z + w[succ(pred(a[i]) mod t[i])];
        delete(w, succ(pred(a[i]) mod t[i]), 1);
        if i = 1 then w := '0' + w;
      end;
    end;
  end else if n > 0 then str(n, z) else z := 'no solutions';
  writeln('r = ', z);
  readkey;
end.
__________________
Действовать надо тупо и это лучшее доказательство нашей чистоты и силы!

Последний раз редактировалось Ghost; 18.03.2005 в 10:02. Причина: склероZzz...
Ghost вне форума