Подразделы

Другие разделы

Дата и время

27/04/2024 06:42:43

Авторизация

Имя:
Пароль:
Зарегистрироваться
Восстановить пароль
 

printРешение задачи Возрастающие числа

Тема: динамическое программирование

Все возможные "возрастающие числа" занесем в массив `"num"` в лексикографическом порядке:
type numinf=record val,len:longint; end;
const num:array[1..39] of numinf=(
(val:1;len:2),(val:123;len:4),(val:1234;len:4),
  (val:12345;len:4),(val:123456;len:4),(val:12;len:3),
(val:2;len:2),(val:234;len:4),(val:2345;len:4),
  (val:23456;len:4),(val:234567;len:4),(val:23;len:3),
...
(val:8;len:2),(val:89;len:3),
(val:9;len:2));
Минимальную длину будем получать в массиве `"minlen"`:
  minlen:array[0..1000000] of longint;
который нужно инициализировать следующим образом:
for i:=1 to n do { для значений, которые еще не обработаны }
  minlen[i]:=1000000; { установить достаточно большое число }
minlen[0]:=0; { 0 можно получить с помощью строки нулевой длины }
Теперь, двигаясь по таблице от 0 до `n`, узнаем самую короткую длину разложения числа `i` на возрастающие числа. Используется принцип динамического программирования: из оптимального решения подзадач можно получить оптимальное решение всей задачи.
for i:=0 to n do
  begin
    { добавляем к лучшему способу получения числа i
      все возможные возрастающие числа }
    for j:=1 to 39 do
      begin
        k:=i+num[j].val;
        { получаем новый способ получения числа k }
        if (k<=n) and (minlen[k]>minlen[i]+num[j].len) then
           { если длина этого способа меньше, запоминаем его в массиве }
          minlen[k]:=minlen[i]+num[j].len;
      end;
  end;
Обратная трассировка по массиву `"minlen"`:
s:='';
while n>0 do
  begin
    { рассматриваем возрастающие числа в лексикографическом порядке }
    for j:=1 to 39 do
      begin
        k:=n-num[j].val;
        if (k>=0) and (minlen[k]+num[j].len=minlen[n]) then
          { если с помощью этого числа получается способ,
            дающий нужную минимальную длину, 
            то используем именно это число }
          begin
            { добавляем возрастающее число к строке-результату }
            str(num[j].val,ss);
            if length(ss)<=2 then
              s:=s+ss+'+'
            else
              s:=s+ss[1]+'-'+ss[length(ss)]+'+';
            n:=k; { уменьшаем искомое число на возрастающее число }
            break;
          end;
      end;
  end;
{ выводим строку-результат без последнего символа '+' }
writeln(copy(s,1,length(s)-1));
loading